diff --git a/CMakeLists.txt b/CMakeLists.txt index 98c88a1..afc45c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,9 +10,4 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) add_subdirectory(borders-plus-plus) add_subdirectory(csgo-vulkan-fix) add_subdirectory(hyprbars) -add_subdirectory(hyprexpo) add_subdirectory(hyprfocus) -add_subdirectory(hyprscrolling) -add_subdirectory(hyprtrails) -add_subdirectory(hyprwinwrap) -add_subdirectory(xtra-dispatchers) diff --git a/README.md b/README.md index d354c05..504da82 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,14 @@ -# hyprland-plugins +## hyprland-plugins This repo houses official plugins for Hyprland. -# Plugin list +## Plugin list - borders-plus-plus -> adds one or two additional borders to windows - csgo-vulkan-fix -> fixes custom resolutions on CS:GO with `-vulkan` - hyprbars -> adds title bars to windows - - hyprexpo -> adds an expo-like workspace overview - hyprfocus -> flashfocus for hyprland - - hyprscrolling -> adds a scrolling layout to hyprland - - hyprtrails -> adds smooth trails behind moving windows - - hyprwinwrap -> clone of xwinwrap, allows you to put any app as a wallpaper - - xtra-dispatchers -> adds some new dispatchers -# Install +## Install > [!IMPORTANT] > hyprland-plugins only officially supports installation via `hyprpm`. > `hyprpm` automatically detects your hyprland version & installs only @@ -21,7 +16,7 @@ This repo houses official plugins for Hyprland. > If you want the latest commits to hyprland-plugins, you need to use > `hyprland-git`. -## Install with `hyprpm` +### Install with `hyprpm` To install these plugins, from the command line run: ```bash @@ -40,7 +35,7 @@ See the respective README's in the subdirectories for configuration options. See [the plugins wiki](https://wiki.hyprland.org/Plugins/Using-Plugins/#installing--using-plugins) and `hyprpm -h` for more details. -## Install on Nix +### Install on Nix To use these plugins, it's recommended that you are already using the [Hyprland flake](https://github.com/hyprwm/Hyprland). @@ -105,8 +100,6 @@ And in `hyprland.conf` exec-once = hyprctl plugin load "$HYPR_PLUGIN_DIR/lib/libhyprexpo.so" ``` -# Contributing +## Contributing Feel free to open issues and MRs with fixes. - -If you want your plugin added here, contact vaxry beforehand. diff --git a/flake.lock b/flake.lock index 1dcaed1..fe46f16 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ ] }, "locked": { - "lastModified": 1776876344, - "narHash": "sha256-Ubqb/agkuMJK+k19gjQgHux/eOYRc1sRGoOZOho8+VY=", + "lastModified": 1777499565, + "narHash": "sha256-nU55VWk99Pn1QzQDDjFISocC4SgDZ3Xp+zb6ji3JclM=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "648a13d0ee1e03a843b3e145b8ece15393058701", + "rev": "813c1e8981893c11e118b19c125d6bc282f51765", "type": "github" }, "original": { @@ -146,11 +146,11 @@ "xdph": "xdph" }, "locked": { - "lastModified": 1777469508, - "narHash": "sha256-2j6wX8051O5KcLw03t9x/RsFUOIGmQ2BPMMEO//iF1o=", + "lastModified": 1778588655, + "narHash": "sha256-7zcsu103YzjuBBx3ToFodHBQl8W3e5GBu8C915I538Y=", "owner": "hyprwm", "repo": "Hyprland", - "rev": "202cf48ecf627839c0a7433cbeb018c744214390", + "rev": "d61c96913cbe3c3f9aacc198b1f1e6489349615d", "type": "github" }, "original": { @@ -246,11 +246,11 @@ ] }, "locked": { - "lastModified": 1776426736, - "narHash": "sha256-rl7i4aY+9p8LysJp7o8uRWahCkpFznCgGHXszlTw7b0=", + "lastModified": 1777320127, + "narHash": "sha256-Qu+Wf2Bp5qUjyn2YpZNq8a7JyzTGowhT1knrwE38a9U=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "7833ff33b2e82d3406337b5dcf0d1cec595d83e9", + "rev": "090117506ddc3d7f26e650ff344d378c2ec329cc", "type": "github" }, "original": { @@ -323,11 +323,11 @@ ] }, "locked": { - "lastModified": 1777148223, - "narHash": "sha256-PTf7kRFFzCW6rIYxLH2fWfVJmj86FSYe3k6L8B+IM9o=", + "lastModified": 1778234770, + "narHash": "sha256-jAcsogZwWMfXT9MfXxZzkwliAqIuZUV0p71h6Ba9ReE=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "fa3992be2dfebe4ab06d753c6ca59bea298e798f", + "rev": "a2dbd8a4cc51f7cbe4224732668392bb1aa79df2", "type": "github" }, "original": { @@ -348,11 +348,11 @@ ] }, "locked": { - "lastModified": 1777148232, - "narHash": "sha256-Uv0WZLhu89SafuSOmYDA7akrPt4wBRmsa1ucasO5aXg=", + "lastModified": 1777159683, + "narHash": "sha256-Jxixw6wZphUp+nHYxOKUYSckL17QMBx2d5Zp0rJHr1g=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "fec9cf1abcc1011e46f0a0986f46bf93c6bf8b92", + "rev": "b8632713a6beaf28b56f2a7b0ab2fb7088dbb404", "type": "github" }, "original": { @@ -377,11 +377,11 @@ ] }, "locked": { - "lastModified": 1776728575, - "narHash": "sha256-z9eGphrArEBpl1O/GCH0wlY6z4K9vA6yWh2gAS6qytU=", + "lastModified": 1777388329, + "narHash": "sha256-40YxVGF2rA9iH3D7am5fy4EOSBbMgpJtJ9yhl0Cx+qI=", "owner": "hyprwm", "repo": "hyprwire", - "rev": "f3a80888783702a39691b684d099e16b83ed4702", + "rev": "04be2897e05f9b271d532b5ae56ca088d2eeac02", "type": "github" }, "original": { @@ -392,11 +392,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1776877367, - "narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=", + "lastModified": 1777954456, + "narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0726a0ecb6d4e08f6adced58726b95db924cef57", + "rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1", "type": "github" }, "original": { @@ -485,11 +485,11 @@ ] }, "locked": { - "lastModified": 1777035886, - "narHash": "sha256-m1TNuBoSXUBSKhD9UVMkU90M0wFTPTfvIOOltO8IM8A=", + "lastModified": 1777585783, + "narHash": "sha256-JTeWRy42VElroJ0rVdZuVXSoTLsx+NzQfGPKMbtn3SU=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "ecfcdcc781f48821d83e1e2a0e30d7beca0eeb5e", + "rev": "fa50d6fbaff8f42c61071b87b034a90d82a33558", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 0f598d7..619ede6 100644 --- a/flake.nix +++ b/flake.nix @@ -32,11 +32,7 @@ borders-plus-plus csgo-vulkan-fix hyprbars - hyprexpo hyprfocus - hyprtrails - hyprwinwrap - xtra-dispatchers ; }); @@ -53,12 +49,7 @@ borders-plus-plus = callPackage ./borders-plus-plus {}; csgo-vulkan-fix = callPackage ./csgo-vulkan-fix {}; hyprbars = callPackage ./hyprbars {}; - hyprexpo = callPackage ./hyprexpo {}; hyprfocus = callPackage ./hyprfocus {}; - hyprscrolling = callPackage ./hyprscrolling {}; - hyprtrails = callPackage ./hyprtrails {}; - hyprwinwrap = callPackage ./hyprwinwrap {}; - xtra-dispatchers = callPackage ./xtra-dispatchers {}; }; }; }; diff --git a/hyprexpo/CMakeLists.txt b/hyprexpo/CMakeLists.txt deleted file mode 100644 index 6967edf..0000000 --- a/hyprexpo/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.27) - -project(hyprexpo - DESCRIPTION "hyprexpo plugin for Hyprland" - VERSION 0.1 -) - -set(CMAKE_CXX_STANDARD 23) - -file(GLOB_RECURSE SRC "*.cpp") - -add_library(hyprexpo SHARED ${SRC}) - -find_package(PkgConfig REQUIRED) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET - hyprland - libdrm - libinput - libudev - pangocairo - pixman-1 - wayland-server - xkbcommon -) -target_link_libraries(hyprexpo PRIVATE rt PkgConfig::deps) - -install(TARGETS hyprexpo) diff --git a/hyprexpo/ExpoGesture.cpp b/hyprexpo/ExpoGesture.cpp deleted file mode 100644 index 8b729e9..0000000 --- a/hyprexpo/ExpoGesture.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "ExpoGesture.hpp" - -#include "overview.hpp" - -#include -#include -#include - -void CExpoGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) { - ITrackpadGesture::begin(e); - - m_lastDelta = 0.F; - m_firstUpdate = true; - - if (!g_pOverview) - g_pOverview = std::make_unique(Desktop::focusState()->monitor()->m_activeWorkspace); - else { - g_pOverview->selectHoveredWorkspace(); - g_pOverview->setClosing(true); - } -} - -void CExpoGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) { - if (m_firstUpdate) { - m_firstUpdate = false; - return; - } - - if (!g_pOverview) - return; - - m_lastDelta += distance(e); - - if (m_lastDelta <= 0.01) // plugin will crash if swipe ends at <= 0 - m_lastDelta = 0.01; - - g_pOverview->onSwipeUpdate(m_lastDelta); -} - -void CExpoGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) { - if (!g_pOverview) - return; - - g_pOverview->setClosing(false); - g_pOverview->onSwipeEnd(); -} diff --git a/hyprexpo/ExpoGesture.hpp b/hyprexpo/ExpoGesture.hpp deleted file mode 100644 index 40876b8..0000000 --- a/hyprexpo/ExpoGesture.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -class CExpoGesture : public ITrackpadGesture { - public: - CExpoGesture() = default; - virtual ~CExpoGesture() = default; - - virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e); - virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e); - virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e); - - private: - float m_lastDelta = 0.F; - bool m_firstUpdate = false; -}; diff --git a/hyprexpo/Makefile b/hyprexpo/Makefile deleted file mode 100644 index d4be567..0000000 --- a/hyprexpo/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Else exist specifically for clang -ifeq ($(CXX),g++) - EXTRA_FLAGS = --no-gnu-unique -else - EXTRA_FLAGS = -endif - -CXXFLAGS ?= -O2 -CXXFLAGS += -shared -fPIC -std=c++2b -Wno-narrowing - -all: - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_FLAGS) main.cpp overview.cpp ExpoGesture.cpp OverviewPassElement.cpp -o hyprexpo.so `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` -clean: - rm ./hyprexpo.so diff --git a/hyprexpo/OverviewPassElement.cpp b/hyprexpo/OverviewPassElement.cpp deleted file mode 100644 index ef40486..0000000 --- a/hyprexpo/OverviewPassElement.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "OverviewPassElement.hpp" -#include -#include "overview.hpp" - -COverviewPassElement::COverviewPassElement() { - ; -} - -std::vector> COverviewPassElement::draw() { - g_pOverview->fullRender(); - return {}; -} - -bool COverviewPassElement::needsLiveBlur() { - return false; -} - -bool COverviewPassElement::needsPrecomputeBlur() { - return false; -} - -std::optional COverviewPassElement::boundingBox() { - if (!g_pOverview->pMonitor) - return std::nullopt; - - return CBox{{}, g_pOverview->pMonitor->m_size}; -} - -CRegion COverviewPassElement::opaqueRegion() { - if (!g_pOverview->pMonitor) - return CRegion{}; - - return CBox{{}, g_pOverview->pMonitor->m_size}; -} diff --git a/hyprexpo/OverviewPassElement.hpp b/hyprexpo/OverviewPassElement.hpp deleted file mode 100644 index 3a364ec..0000000 --- a/hyprexpo/OverviewPassElement.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include - -class COverview; - -class COverviewPassElement : public IPassElement { - public: - COverviewPassElement(); - virtual ~COverviewPassElement() = default; - - 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() override { - return "COverviewPassElement"; - } -}; diff --git a/hyprexpo/README.md b/hyprexpo/README.md deleted file mode 100644 index cbc9d07..0000000 --- a/hyprexpo/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# HyprExpo -HyprExpo is an overview plugin like Gnome, KDE or wf. - -![HyprExpo](https://github.com/user-attachments/assets/e89df9d2-9800-4268-9929-239ad9bc3a54) - -## Config -A great start to configure this plugin would be adding this code to the `plugin` section of your hyprland configuration file: -```ini -# .config/hypr/hyprland.conf -plugin { - hyprexpo { - columns = 3 - gap_size = 5 - bg_col = rgb(111111) - workspace_method = center current # [center/first] [workspace] e.g. first 1 or center m+1 - - gesture_distance = 300 # how far is the "max" for the gesture - } -} -``` - -### Properties - -| property | type | description | default | -| --- | --- | --- | --- | -columns | number | how many desktops are displayed on one line | `3` -gap_size | number | gap between desktops | `5` -bg_col | color | color in gaps (between desktops) | `rgb(000000)` -workspace_method | [center/first] [workspace] | position of the desktops | `center current` -skip_empty | boolean | whether the grid displays workspaces sequentially by id using selector "r" (`false`) or skips empty workspaces using selector "m" (`true`) | `false` -gesture_distance | number | how far is the max for the gesture | `300` - -### Keywords - -| name | description | arguments | -| -- | -- | -- | -| hyprexpo-gesture | same as gesture, but for hyprexpo gestures. Supports: `expo`. | Same as gesture | - -### Binding -```bash -# hyprland.conf -bind = MODIFIER, KEY, hyprexpo:expo, OPTION -``` - -Example: -```bash -# This will toggle HyprExpo when SUPER+g is pressed -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/default.nix b/hyprexpo/default.nix deleted file mode 100644 index 0d28d66..0000000 --- a/hyprexpo/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - lib, - hyprland, - hyprlandPlugins, -}: -hyprlandPlugins.mkHyprlandPlugin { - pluginName = "hyprexpo"; - version = "0.1"; - src = ./.; - - inherit (hyprland) nativeBuildInputs; - - meta = with lib; { - homepage = "https://github.com/hyprwm/hyprland-plugins/tree/main/hyprexpo"; - description = "Hyprland workspaces overview plugin"; - license = licenses.bsd3; - platforms = platforms.linux; - }; -} diff --git a/hyprexpo/globals.hpp b/hyprexpo/globals.hpp deleted file mode 100644 index 2257475..0000000 --- a/hyprexpo/globals.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -inline HANDLE PHANDLE = nullptr; \ No newline at end of file diff --git a/hyprexpo/main.cpp b/hyprexpo/main.cpp deleted file mode 100644 index 65521f4..0000000 --- a/hyprexpo/main.cpp +++ /dev/null @@ -1,338 +0,0 @@ -#define WLR_USE_UNSTABLE - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -using namespace Hyprutils::String; - -#include "globals.hpp" -#include "overview.hpp" -#include "ExpoGesture.hpp" - -// Methods -inline CFunctionHook* g_pRenderWorkspaceHook = nullptr; -inline CFunctionHook* g_pAddDamageHookA = nullptr; -inline CFunctionHook* g_pAddDamageHookB = nullptr; -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*); - -static bool g_unloading = false; - -// Do NOT change this function. -APICALL EXPORT std::string PLUGIN_API_VERSION() { - return HYPRLAND_API_VERSION; -} - -static bool renderingOverview = false; - -const std::string KEYWORD_EXPO_GESTURE = "hyprexpo-gesture"; - -// -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 - g_pOverview->render(); -} - -static void hkAddDamageA(void* thisptr, const CBox& box) { - const auto PMONITOR = (CMonitor*)thisptr; - - if (!g_pOverview || g_pOverview->pMonitor != PMONITOR->m_self || g_pOverview->blockDamageReporting) { - ((origAddDamageA)g_pAddDamageHookA->m_original)(thisptr, box); - return; - } - - g_pOverview->onDamageReported(); -} - -static void hkAddDamageB(void* thisptr, const pixman_region32_t* rg) { - const auto PMONITOR = (CMonitor*)thisptr; - - if (!g_pOverview || g_pOverview->pMonitor != PMONITOR->m_self || g_pOverview->blockDamageReporting) { - ((origAddDamageB)g_pAddDamageHookB->m_original)(thisptr, rg); - return; - } - - 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) - return {.success = false, .error = "already swiping"}; - - if (arg == "select") { - if (g_pOverview) { - g_pOverview->selectHoveredWorkspace(); - g_pOverview->close(); - } - 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(); - else { - renderingOverview = true; - g_pOverview = std::make_unique(Desktop::focusState()->monitor()->m_activeWorkspace); - renderingOverview = false; - } - return {}; - } - - if (arg == "off" || arg == "close" || arg == "disable") { - if (g_pOverview) - g_pOverview->close(); - return {}; - } - - if (g_pOverview) - return {}; - - renderingOverview = true; - g_pOverview = std::make_unique(Desktop::focusState()->monitor()->m_activeWorkspace); - renderingOverview = false; - 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; - - if (g_unloading) - return result; - - CConstVarList data(RHS); - - size_t fingerCount = 0; - eTrackpadGestureDirection direction = TRACKPAD_GESTURE_DIR_NONE; - - try { - fingerCount = std::stoul(std::string{data[0]}); - } catch (...) { - result.setError(std::format("Invalid value {} for finger count", data[0]).c_str()); - return result; - } - - if (fingerCount <= 1 || fingerCount >= 10) { - result.setError(std::format("Invalid value {} for finger count", data[0]).c_str()); - return result; - } - - direction = g_pTrackpadGestures->dirForString(data[1]); - - if (direction == TRACKPAD_GESTURE_DIR_NONE) { - result.setError(std::format("Invalid direction: {}", data[1]).c_str()); - return result; - } - - int startDataIdx = 2; - uint32_t modMask = 0; - float deltaScale = 1.F; - bool disableInhibit = false; - - for (const auto arg : std::string(LHS).substr(KEYWORD_EXPO_GESTURE.size())) { - switch (arg) { - case 'p': disableInhibit = true; break; - default: result.setError("hyprexpo-gesture: invalid flag"); return result; - } - } - - while (true) { - - if (data[startDataIdx].starts_with("mod:")) { - modMask = g_pKeybindManager->stringToModMask(std::string{data[startDataIdx].substr(4)}); - startDataIdx++; - continue; - } else if (data[startDataIdx].starts_with("scale:")) { - try { - deltaScale = std::clamp(std::stof(std::string{data[startDataIdx].substr(6)}), 0.1F, 10.F); - startDataIdx++; - continue; - } catch (...) { - result.setError(std::format("Invalid delta scale: {}", std::string{data[startDataIdx].substr(6)}).c_str()); - return result; - } - } - - break; - } - - std::expected resultFromGesture; - - if (data[startDataIdx] == "expo") - resultFromGesture = g_pTrackpadGestures->addGesture(makeUnique(), fingerCount, direction, modMask, deltaScale, disableInhibit); - else if (data[startDataIdx] == "unset") - resultFromGesture = g_pTrackpadGestures->removeGesture(fingerCount, direction, modMask, deltaScale, disableInhibit); - else { - result.setError(std::format("Invalid gesture: {}", data[startDataIdx]).c_str()); - return result; - } - - if (!resultFromGesture) { - result.setError(resultFromGesture.error().c_str()); - return result; - } - - return result; -} - -APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { - PHANDLE = handle; - - const std::string HASH = __hyprland_api_get_hash(); - const std::string CLIENT_HASH = __hyprland_api_get_client_hash(); - - if (HASH != CLIENT_HASH) { - failNotif("Version mismatch (headers ver is not equal to running hyprland ver)"); - throw std::runtime_error("[he] Version mismatch"); - } - - auto FNS = HyprlandAPI::findFunctionsByName(PHANDLE, "renderWorkspace"); - if (FNS.empty()) { - failNotif("no fns for hook renderWorkspace"); - throw std::runtime_error("[he] No fns for hook renderWorkspace"); - } - - g_pRenderWorkspaceHook = HyprlandAPI::createFunctionHook(PHANDLE, FNS[0].address, (void*)hkRenderWorkspace); - - FNS = HyprlandAPI::findFunctionsByName(PHANDLE, "addDamageEPK15pixman_region32"); - if (FNS.empty()) { - failNotif("no fns for hook addDamageEPK15pixman_region32"); - throw std::runtime_error("[he] No fns for hook addDamageEPK15pixman_region32"); - } - - g_pAddDamageHookB = HyprlandAPI::createFunctionHook(PHANDLE, FNS[0].address, (void*)hkAddDamageB); - - FNS = HyprlandAPI::findFunctionsByName(PHANDLE, "_ZN8CMonitor9addDamageERKN9Hyprutils4Math4CBoxE"); - if (FNS.empty()) { - failNotif("no fns for hook _ZN8CMonitor9addDamageERKN9Hyprutils4Math4CBoxE"); - throw std::runtime_error("[he] No fns for hook _ZN8CMonitor9addDamageERKN9Hyprutils4Math4CBoxE"); - } - - g_pAddDamageHookA = HyprlandAPI::createFunctionHook(PHANDLE, FNS[0].address, (void*)hkAddDamageA); - - bool success = g_pRenderWorkspaceHook->hook(); - success = success && g_pAddDamageHookA->hook(); - success = success && g_pAddDamageHookB->hook(); - - if (!success) { - failNotif("Failed initializing hooks"); - throw std::runtime_error("[he] Failed initializing hooks"); - } - - static auto P = Event::bus()->m_events.render.pre.listen([](PHLMONITOR) { - if (!g_pOverview) - return; - g_pOverview->onPreRender(); - }); - - HyprlandAPI::addDispatcherV2(PHANDLE, "hyprexpo:expo", ::onExpoDispatcher); - HyprlandAPI::addLuaFunction(PHANDLE, "hyprexpo", "expo", ::luaExpo); - - HyprlandAPI::addConfigKeyword(PHANDLE, KEYWORD_EXPO_GESTURE, ::expoGestureKeyword, {true}); - - 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"}; -} - -APICALL EXPORT void PLUGIN_EXIT() { - g_pHyprRenderer->m_renderPass.removeAllOfType("COverviewPassElement"); - - g_unloading = true; - - Config::mgr()->reload(); // we need to reload now to clear all the gestures -} diff --git a/hyprexpo/meson.build b/hyprexpo/meson.build deleted file mode 100644 index 6a68ab0..0000000 --- a/hyprexpo/meson.build +++ /dev/null @@ -1,38 +0,0 @@ -project('hyprexpo', 'cpp', - version: '0.1', - default_options: ['buildtype=release'], -) - -cpp_compiler = meson.get_compiler('cpp') -if cpp_compiler.has_argument('-std=c++23') - add_global_arguments('-std=c++23', language: 'cpp') -elif cpp_compiler.has_argument('-std=c++2b') - add_global_arguments('-std=c++2b', language: 'cpp') -else - error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') -endif - -add_project_arguments( - [ - '-Wno-narrowing', - ], - language: 'cpp') - -globber = run_command('find', '.', '-name', '*.cpp', check: true) -src = globber.stdout().strip().split('\n') - -hyprland = dependency('hyprland') - -shared_module(meson.project_name(), src, - dependencies: [ - dependency('hyprland'), - dependency('pixman-1'), - dependency('libdrm'), - dependency('pangocairo'), - dependency('libinput'), - dependency('libudev'), - dependency('wayland-server'), - dependency('xkbcommon'), - ], - install: true, -) diff --git a/hyprexpo/overview.cpp b/hyprexpo/overview.cpp deleted file mode 100644 index 097280c..0000000 --- a/hyprexpo/overview.cpp +++ /dev/null @@ -1,553 +0,0 @@ -#include "overview.hpp" -#include -#include -#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() { - Render::GL::g_pHyprOpenGL->makeEGLCurrent(); - images.clear(); // otherwise we get a vram leak - Cursor::overrideController->unsetOverride(Cursor::CURSOR_OVERRIDE_UNKNOWN); - 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 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 = CHyprColor(*PCOL); - - // process the method - bool methodCenter = true; - int methodStartID = pMonitor->activeWorkspaceID(); - CVarList method{*PMETHOD, 0, 's', true}; - if (method.size() < 2) - Log::logger->log(Log::ERR, "[he] invalid workspace_method"); - else { - methodCenter = method[0] == "center"; - methodStartID = getWorkspaceIDNameFromString(method[1]).id; - if (methodStartID == WORKSPACE_INVALID) - methodStartID = pMonitor->activeWorkspaceID(); - } - - images.resize(SIDE_LENGTH * SIDE_LENGTH); - - // r includes empty workspaces; m skips over them - std::string selector = *PSKIP ? "m" : "r"; - - if (methodCenter) { - int currentID = methodStartID; - int firstID = currentID; - - int backtracked = 0; - - // Initialize tiles to WORKSPACE_INVALID; cliking one of these results - // in changing to "emptynm" (next empty workspace). Tiles with this id - // will only remain if skip_empty is on. - for (size_t i = 0; i < images.size(); i++) { - images[i].workspaceID = WORKSPACE_INVALID; - } - - // Scan through workspaces lower than methodStartID until we wrap; count how many - for (size_t i = 1; i < images.size() / 2; ++i) { - currentID = getWorkspaceIDNameFromString(selector + "-" + std::to_string(i)).id; - if (currentID >= firstID) - break; - - backtracked++; - firstID = currentID; - } - - // Scan through workspaces higher than methodStartID. If using "m" - // (skip_empty), stop when we wrap, leaving the rest of the workspace - // ID's set to WORKSPACE_INVALID - for (size_t i = 0; i < (size_t)(SIDE_LENGTH * SIDE_LENGTH); ++i) { - auto& image = images[i]; - if ((int64_t)i - backtracked < 0) { - currentID = getWorkspaceIDNameFromString(selector + std::to_string((int64_t)i - backtracked)).id; - } else { - currentID = getWorkspaceIDNameFromString(selector + "+" + std::to_string((int64_t)i - backtracked)).id; - if (i > 0 && currentID == firstID) - break; - } - image.workspaceID = currentID; - } - - } else { - int currentID = methodStartID; - images[0].workspaceID = currentID; - - auto PWORKSPACESTART = g_pCompositor->getWorkspaceByID(currentID); - if (!PWORKSPACESTART) - PWORKSPACESTART = CWorkspace::create(currentID, pMonitor.lock(), std::to_string(currentID)); - - pMonitor->m_activeWorkspace = PWORKSPACESTART; - - // Scan through workspaces higher than methodStartID. If using "m" - // (skip_empty), stop when we wrap, leaving the rest of the workspace - // ID's set to WORKSPACE_INVALID - for (size_t i = 1; i < (size_t)(SIDE_LENGTH * SIDE_LENGTH); ++i) { - auto& image = images[i]; - currentID = getWorkspaceIDNameFromString(selector + "+" + std::to_string(i)).id; - if (currentID <= methodStartID) - break; - image.workspaceID = currentID; - } - - pMonitor->m_activeWorkspace = startedOn; - } - - 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; - CBox monbox{0, 0, tileSize.x * 2, tileSize.y * 2}; - - if (!ENABLE_LOWRES) - monbox = {{0, 0}, pMonitor->m_pixelSize}; - - int currentid = 0; - - PHLWORKSPACE openSpecial = PMONITOR->m_activeSpecialWorkspace; - if (openSpecial) - PMONITOR->m_activeSpecialWorkspace.reset(); - - g_pHyprRenderer->m_bBlockSurfaceFeedback = true; - - startedOn->m_visible = false; - - for (size_t i = 0; i < (size_t)(SIDE_LENGTH * SIDE_LENGTH); ++i) { - COverview::SWorkspaceImage& image = images[i]; - ensureFramebuffer(image, monbox, framebufferFormatWithAlpha(PMONITOR->m_output->state->state().drmFormat)); - - CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; - g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, Render::RENDER_MODE_FULL_FAKE, nullptr, image.fb); - - clearWithColor(CHyprColor{0, 0, 0, 1.0}); - - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(image.workspaceID); - - if (PWORKSPACE == startedOn) - currentid = i; - - if (PWORKSPACE) { - image.pWorkspace = PWORKSPACE; - PMONITOR->m_activeWorkspace = PWORKSPACE; - g_pDesktopAnimationManager->startAnimation(PWORKSPACE, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true); - PWORKSPACE->m_visible = true; - - if (PWORKSPACE == startedOn) - PMONITOR->m_activeSpecialWorkspace = openSpecial; - - g_pHyprRenderer->renderWorkspace(PMONITOR, PWORKSPACE, Time::steadyNow(), monbox); - - PWORKSPACE->m_visible = false; - g_pDesktopAnimationManager->startAnimation(PWORKSPACE, CDesktopAnimationManager::ANIMATION_TYPE_OUT, false, true); - - if (PWORKSPACE == startedOn) - PMONITOR->m_activeSpecialWorkspace.reset(); - } else - g_pHyprRenderer->renderWorkspace(PMONITOR, PWORKSPACE, Time::steadyNow(), monbox); - - 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_pHyprRenderer->m_renderData.blockScreenShader = true; - g_pHyprRenderer->endRender(); - } - - g_pHyprRenderer->m_bBlockSurfaceFeedback = false; - - PMONITOR->m_activeSpecialWorkspace = openSpecial; - PMONITOR->m_activeWorkspace = startedOn; - startedOn->m_visible = true; - g_pDesktopAnimationManager->startAnimation(startedOn, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true); - - // 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, 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, Config::animationTree()->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); - - size->setUpdateCallback(damageMonitor); - pos->setUpdateCallback(damageMonitor); - - if (!swipe) { - *size = pMonitor->m_size; - *pos = {0, 0}; - - size->setCallbackOnEnd([this](auto) { redrawAll(true); }); - } - - openedID = currentid; - - Cursor::overrideController->setOverride("left_ptr", Cursor::CURSOR_OVERRIDE_UNKNOWN); - - lastMousePosLocal = g_pInputManager->getMouseCoordsInternal() - pMonitor->m_position; - - auto onCursorMove = [this](Event::SCallbackInfo& info) { - if (closing) - return; - - info.cancelled = true; - lastMousePosLocal = g_pInputManager->getMouseCoordsInternal() - pMonitor->m_position; - }; - - auto onCursorSelect = [this](Event::SCallbackInfo& info) { - if (closing) - return; - - info.cancelled = true; - - selectHoveredWorkspace(); - - close(); - }; - - mouseMoveHook = Event::bus()->m_events.input.mouse.move.listen([onCursorMove](Vector2D, Event::SCallbackInfo& info) { onCursorMove(info); }); - touchMoveHook = Event::bus()->m_events.input.touch.motion.listen([onCursorMove](ITouch::SMotionEvent, Event::SCallbackInfo& info) { onCursorMove(info); }); - - mouseButtonHook = Event::bus()->m_events.input.mouse.button.listen([onCursorSelect](IPointer::SButtonEvent, Event::SCallbackInfo& info) { onCursorSelect(info); }); - touchDownHook = Event::bus()->m_events.input.touch.down.listen([onCursorSelect](ITouch::SDownEvent, Event::SCallbackInfo& info) { onCursorSelect(info); }); -} - -void COverview::selectHoveredWorkspace() { - if (closing) - return; - - // get tile x,y - 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) { - if (!pMonitor) - return; - - if (pMonitor->m_activeWorkspace != startedOn && !closing) { - // likely user changed. - onWorkspaceChange(); - } - - blockOverviewRendering = true; - - Render::GL::g_pHyprOpenGL->makeEGLCurrent(); - - 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; - CBox monbox{0, 0, tileSize.x * 2, tileSize.y * 2}; - - if (!forcelowres && (size->value() != pMonitor->m_size || closing)) - monbox = {{0, 0}, pMonitor->m_pixelSize}; - - if (!ENABLE_LOWRES) - monbox = {{0, 0}, pMonitor->m_pixelSize}; - - auto& image = images[id]; - - 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::RENDER_MODE_FULL_FAKE, nullptr, image.fb); - - clearWithColor(CHyprColor{0, 0, 0, 1.0}); - - const auto PWORKSPACE = image.pWorkspace; - - PHLWORKSPACE openSpecial = pMonitor->m_activeSpecialWorkspace; - if (openSpecial) - pMonitor->m_activeSpecialWorkspace.reset(); - - startedOn->m_visible = false; - - if (PWORKSPACE) { - pMonitor->m_activeWorkspace = PWORKSPACE; - g_pDesktopAnimationManager->startAnimation(PWORKSPACE, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true); - PWORKSPACE->m_visible = true; - - if (PWORKSPACE == startedOn) - pMonitor->m_activeSpecialWorkspace = openSpecial; - - g_pHyprRenderer->renderWorkspace(pMonitor.lock(), PWORKSPACE, Time::steadyNow(), monbox); - - PWORKSPACE->m_visible = false; - g_pDesktopAnimationManager->startAnimation(PWORKSPACE, CDesktopAnimationManager::ANIMATION_TYPE_OUT, false, true); - - if (PWORKSPACE == startedOn) - pMonitor->m_activeSpecialWorkspace.reset(); - } else - g_pHyprRenderer->renderWorkspace(pMonitor.lock(), PWORKSPACE, Time::steadyNow(), monbox); - - g_pHyprRenderer->m_renderData.blockScreenShader = true; - g_pHyprRenderer->endRender(); - - pMonitor->m_activeSpecialWorkspace = openSpecial; - pMonitor->m_activeWorkspace = startedOn; - startedOn->m_visible = true; - g_pDesktopAnimationManager->startAnimation(startedOn, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true); - - blockOverviewRendering = false; -} - -void COverview::redrawAll(bool forcelowres) { - if (!pMonitor) - return; - for (size_t i = 0; i < (size_t)(SIDE_LENGTH * SIDE_LENGTH); ++i) { - redrawID(i, forcelowres); - } -} - -void COverview::damage() { - blockDamageReporting = true; - g_pHyprRenderer->damageMonitor(pMonitor.lock()); - blockDamageReporting = false; -} - -void COverview::onDamageReported() { - damageDirty = true; - - Vector2D SIZE = size->value(); - - Vector2D tileSize = (SIZE / SIDE_LENGTH); - Vector2D tileRenderSize = (SIZE - Vector2D{GAP_WIDTH, GAP_WIDTH} * (SIDE_LENGTH - 1)) / SIDE_LENGTH; - // const auto& TILE = images[std::clamp(openedID, 0, SIDE_LENGTH * SIDE_LENGTH)]; - CBox texbox = CBox{(openedID % SIDE_LENGTH) * tileRenderSize.x + (openedID % SIDE_LENGTH) * GAP_WIDTH, - (openedID / SIDE_LENGTH) * tileRenderSize.y + (openedID / SIDE_LENGTH) * GAP_WIDTH, tileRenderSize.x, tileRenderSize.y} - .translate(pMonitor->m_position); - - damage(); - - blockDamageReporting = true; - g_pHyprRenderer->damageBox(texbox); - blockDamageReporting = false; - g_pCompositor->scheduleFrameForMonitor(pMonitor.lock()); -} - -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 SAFEID = std::clamp(ID, 0, SIDE_LENGTH * SIDE_LENGTH - 1); - - const auto& TILE = images[SAFEID]; - - Vector2D tileSize = (pMonitor->m_size / SIDE_LENGTH); - - size->warp(); - pos->warp(); - - *size = pMonitor->m_size * 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 (switchToSelection && TILE.workspaceID != pMonitor->activeWorkspaceID()) { - pMonitor->setSpecialWorkspace(0); - - // If this tile's workspace was WORKSPACE_INVALID, move to the next - // empty workspace. This should only happen if skip_empty is on, in - // which case some tiles will be left with this ID intentionally. - const int NEWID = TILE.workspaceID == WORKSPACE_INVALID ? getWorkspaceIDNameFromString("emptynm").id : TILE.workspaceID; - - const auto NEWIDWS = g_pCompositor->getWorkspaceByID(NEWID); - - const auto OLDWS = pMonitor->m_activeWorkspace; - - if (!NEWIDWS) - Config::Actions::changeWorkspace(std::to_string(NEWID)); - else - 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); - - startedOn = pMonitor->m_activeWorkspace; - } - - size->setCallbackOnEnd([](auto) { g_pEventLoopManager->doLater([] { g_pOverview.reset(); }); }); -} - -void COverview::onPreRender() { - if (damageDirty) { - damageDirty = false; - redrawID(closing ? (closeOnID == -1 ? openedID : closeOnID) : openedID); - } -} - -void COverview::onWorkspaceChange() { - if (valid(startedOn)) - g_pDesktopAnimationManager->startAnimation(startedOn, CDesktopAnimationManager::ANIMATION_TYPE_OUT, false, true); - else - startedOn = pMonitor->m_activeWorkspace; - - for (size_t i = 0; i < (size_t)(SIDE_LENGTH * SIDE_LENGTH); ++i) { - if (images[i].workspaceID != pMonitor->activeWorkspaceID()) - continue; - - openedID = i; - break; - } - - closeOnID = openedID; - if (!closing) - close(); -} - -void COverview::render() { - g_pHyprRenderer->m_renderPass.add(makeUnique()); -} - -void COverview::fullRender() { - const auto GAPSIZE = (closing ? (1.0 - size->getPercent()) : size->getPercent()) * GAP_WIDTH; - - if (pMonitor->m_activeWorkspace != startedOn && !closing) { - // likely user changed. - onWorkspaceChange(); - } - - Vector2D SIZE = size->value(); - - Vector2D tileSize = (SIZE / SIDE_LENGTH); - Vector2D tileRenderSize = (SIZE - Vector2D{GAPSIZE, GAPSIZE} * (SIDE_LENGTH - 1)) / SIDE_LENGTH; - - 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) { - CBox texbox = {x * tileRenderSize.x + x * GAPSIZE, y * tileRenderSize.y + y * GAPSIZE, tileRenderSize.x, tileRenderSize.y}; - texbox.scale(pMonitor->m_scale).translate(pos->value()); - texbox.round(); - CRegion damage{0, 0, INT16_MAX, INT16_MAX}; - auto& image = images[x + y * SIDE_LENGTH]; - Render::GL::g_pHyprOpenGL->renderTextureInternal(image.fb->getTexture(), texbox, {.damage = &damage, .a = 1.0}); - } - } -} - -static float lerp(const float& from, const float& to, const float perc) { - return (to - from) * perc + from; -} - -static Vector2D lerp(const Vector2D& from, const Vector2D& to, const float perc) { - return Vector2D{lerp(from.x, to.x, perc), lerp(from.y, to.y, perc)}; -} - -void COverview::setClosing(bool closing_) { - closing = closing_; -} - -void COverview::resetSwipe() { - swipeWasCommenced = false; -} - -void COverview::onSwipeUpdate(double delta) { - m_isSwiping = true; - - 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; - - 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) * - (pMonitor->m_size / tileSize); - - const auto SIZEMIN = pMonitor->m_size; - const auto POSMIN = Vector2D{0, 0}; - - size->setValueAndWarp(lerp(SIZEMIN, SIZEMAX, PERC)); - pos->setValueAndWarp(lerp(POSMIN, POSMAX, PERC)); -} - -void COverview::onSwipeEnd() { - if (closing || !m_isSwiping) - return; - - const auto SIZEMIN = pMonitor->m_size; - const auto SIZEMAX = pMonitor->m_size * pMonitor->m_size / (pMonitor->m_size / SIDE_LENGTH); - const auto PERC = (size->value() - SIZEMIN).x / (SIZEMAX - SIZEMIN).x; - if (PERC > 0.5) { - close(); - return; - } - *size = pMonitor->m_size; - *pos = {0, 0}; - - size->setCallbackOnEnd([this](WP thisptr) { redrawAll(true); }); - - swipeWasCommenced = false; - m_isSwiping = false; -} diff --git a/hyprexpo/overview.hpp b/hyprexpo/overview.hpp deleted file mode 100644 index 1cbf2df..0000000 --- a/hyprexpo/overview.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#define WLR_USE_UNSTABLE - -#include "globals.hpp" -#include -#include -#include -#include -#include - -// saves on resources, but is a bit broken rn with blur. -// hyprland's fault, but cba to fix. -constexpr bool ENABLE_LOWRES = false; - -class CMonitor; - -class COverview { - public: - COverview(PHLWORKSPACE startedOn_, bool swipe = false); - ~COverview(); - - void render(); - void damage(); - void onDamageReported(); - void onPreRender(); - - void setClosing(bool closing); - - void resetSwipe(); - void onSwipeUpdate(double delta); - void onSwipeEnd(); - - // close without a selection - void close(bool switchToSelection = true); - void selectHoveredWorkspace(); - int64_t selectedWorkspaceID() const; - - bool blockOverviewRendering = false; - bool blockDamageReporting = false; - - PHLMONITORREF pMonitor; - bool m_isSwiping = false; - - struct SWorkspaceImage { - 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; - int closeOnID = -1; - - std::vector images; - - PHLWORKSPACE startedOn; - - PHLANIMVAR size; - PHLANIMVAR pos; - - bool closing = false; - - CHyprSignalListener mouseMoveHook; - CHyprSignalListener mouseButtonHook; - CHyprSignalListener touchMoveHook; - CHyprSignalListener touchDownHook; - - bool swipe = false; - bool swipeWasCommenced = false; - - friend class COverviewPassElement; -}; - -inline std::unique_ptr g_pOverview; diff --git a/hyprload.toml b/hyprload.toml deleted file mode 100644 index 3a4af45..0000000 --- a/hyprload.toml +++ /dev/null @@ -1,54 +0,0 @@ -[borders-plus-plus] -description ="A plugin to add more borders to windows." -version = "1.0" -authors = ["Vaxry"] - -[borders-plus-plus.build] -output = "borders-plus-plus/borders-plus-plus.so" -steps = [ - "make -C borders-plus-plus all", -] - -[csgo-vulkan-fix] -description = "A plugin to fix incorrect mouse offsets on csgo in Vulkan" -version = "1.0" -authors = ["Vaxry"] - -[csgo-vulkan-fix.build] -output = "csgo-vulkan-fix/csgo-vulkan-fix.so" -steps = [ - "make -C csgo-vulkan-fix all", -] - -[hyprbars] -description = "A plugin to add title bars to windows" -version = "1.0" -authors = ["Vaxry"] - -[hyprbars.build] -output = "hyprbars/hyprbars.so" -steps = [ - "make -C hyprbars all", -] - -[hyprtrails] -description = "A plugin to add trails behind moving windows" -version = "1.0" -authors = ["Vaxry"] - -[hyprtrails.build] -output = "hyprtrails/hyprtrails.so" -steps = [ - "make -C hyprtrails all", -] - -[hyprwinwrap] -description = "A clone of xwinwrap for Hyprland" -version = "1.0" -authors = ["Vaxry"] - -[hyprwinwrap.build] -output = "hyprwinwrap/hyprwinwrap.so" -steps = [ - "make -C hyprwinwrap all", -] diff --git a/hyprpm.toml b/hyprpm.toml index dfb01dd..1e2b5a7 100644 --- a/hyprpm.toml +++ b/hyprpm.toml @@ -73,49 +73,6 @@ build = [ "make -C hyprbars all", ] -[hyprtrails] -description = "A plugin to add trails behind moving windows" -authors = ["Vaxry"] -output = "hyprtrails/hyprtrails.so" -build = [ - "make -C hyprtrails all", -] - -[hyprwinwrap] -description = "A clone of xwinwrap for Hyprland" -authors = ["Vaxry"] -output = "hyprwinwrap/hyprwinwrap.so" -build = [ - "make -C hyprwinwrap all", -] - -[hyprexpo] -description = "A plugin to add expo (overlay) for workspaces" -authors = ["Vaxry"] -output = "hyprexpo/hyprexpo.so" -build = [ - "make -C hyprexpo all", -] -since_hyprland = 4364 - -[xtra-dispatchers] -description = "A plugin to add some extra dispatchers" -authors = ["Vaxry"] -output = "xtra-dispatchers/xtra-dispatchers.so" -build = [ - "make -C xtra-dispatchers all", -] -since_hyprland = 5573 - -[hyprscrolling] -description = "A plugin to add a scrolling layout" -authors = ["Vaxry"] -output = "hyprscrolling/hyprscrolling.so" -build = [ - "make -C hyprscrolling all", -] -since_hyprland = 6066 - [hyprfocus] description = "Flashfocus for Hyprland" authors = ["Vaxry"] diff --git a/hyprscrolling/CMakeLists.txt b/hyprscrolling/CMakeLists.txt deleted file mode 100644 index 2a05e9f..0000000 --- a/hyprscrolling/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.27) - -project(hyprscrolling - DESCRIPTION "hyprscrolling plugin for Hyprland" - VERSION 0.1 -) - -set(CMAKE_CXX_STANDARD 23) - -file(GLOB_RECURSE SRC "*.cpp") - -add_library(hyprscrolling SHARED ${SRC}) - -find_package(PkgConfig REQUIRED) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET - hyprland - libdrm - libinput - libudev - pangocairo - pixman-1 - wayland-server - xkbcommon -) -target_link_libraries(hyprscrolling PRIVATE rt PkgConfig::deps) - -install(TARGETS hyprscrolling) diff --git a/hyprscrolling/Makefile b/hyprscrolling/Makefile deleted file mode 100644 index 1471912..0000000 --- a/hyprscrolling/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Else exist specifically for clang -ifeq ($(CXX),g++) - EXTRA_FLAGS = --no-gnu-unique -else - EXTRA_FLAGS = -endif - -CXXFLAGS ?= -O2 -CXXFLAGS += -shared -fPIC -std=c++2b - -all: - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_FLAGS) main.cpp Scrolling.cpp -o hyprscrolling.so `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` -clean: - rm ./hyprscrolling.so diff --git a/hyprscrolling/README.md b/hyprscrolling/README.md deleted file mode 100644 index 1407c0a..0000000 --- a/hyprscrolling/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# hyprscrolling - -Adds a scrolling layout to Hyprland. - -**This plugin is a work in progress!** - -## Config - -Make sure to set the `general:layout` to `scrolling` to use this layout. - -All config values can be set in your Hyprland config file, for example: - -``` -plugin { - hyprscrolling { - column_width = 0.7 - fullscreen_on_one_column = false - } -} -``` - -| name | description | type | default | -| -- | -- | -- | -- | -| fullscreen_on_one_column | if there's only one column, should it be fullscreen | bool | false | -| column_width | default column width as a fraction of the monitor width | float [0 - 1] | 0.5 | -| explicit_column_widths | a comma-separated list of widths for columns to be used with `+conf` or `-conf` | string | `0.333, 0.5, 0.667, 1.0` | -| focus_fit_method | when a column is focused, what method to use to bring it into view. 0 - center, 1 - fit | int | 0 | -| follow_focus | when a window is focused, the layout will move to make it visible | bool | true | -| follow_debounce_ms | time to debounce focus events for | int | 0 | - -## Layout messages - -| name | description | params | -| --- | --- | --- | -| move | move the layout horizontally, by either a relative logical px (`-200`, `+200`) or columns (`+col`, `-col`) | move data | -| colresize | resize the current column, to either a value or by a relative value e.g. `0.5`, `+0.2`, `-0.2` or cycle the preconfigured ones with `+conf` or `-conf`. Can also be `all (number)` for resizing all columns to a specific width | relative float / relative conf | -| movewindowto | same as the movewindow dispatcher but supports promotion to the right at the end | direction | -| fit | executes a fit operation based on the argument. Available: `active`, `visible`, `all`, `toend`, `tobeg` | fit mode | -| focus | moves the focus and centers the layout, while also wrapping instead of moving to neighbring monitors. | direction | -| promote | moves a window to its own new column | none | -| swapcol | Swaps the current column with its neighbor to the left (`l`) or right (`r`). The swap wraps around (e.g., swapping the first column left moves it to the end). | `l` or `r` | -| movecoltoworkspace | Moves the entire current column to the specified workspace, preserving its internal layout. Works with existing, new, and special workspaces. e.g. like `1`, `2`, `-1`, `+2`, `special`, etc. | workspace identifier| -| togglefit | Toggle the focus_fit_method (center, fit) | none | - -Example key bindings for your Hyprland config: - -``` -bind = $mainMod, period, layoutmsg, move +col -bind = $mainMod, comma, layoutmsg, move -col -bind = $mainMod SHIFT, period, layoutmsg, movewindowto r -bind = $mainMod SHIFT, comma, layoutmsg, movewindowto l -bind = $mainMod SHIFT, up, layoutmsg, movewindowto u -bind = $mainMod SHIFT, down, layoutmsg, movewindowto d -``` diff --git a/hyprscrolling/Scrolling.cpp b/hyprscrolling/Scrolling.cpp deleted file mode 100644 index bd9613c..0000000 --- a/hyprscrolling/Scrolling.cpp +++ /dev/null @@ -1,1552 +0,0 @@ -#include "Scrolling.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -using namespace Hyprutils::String; -using namespace Hyprutils::Utils; - -constexpr float MIN_COLUMN_WIDTH = 0.05F; -constexpr float MAX_COLUMN_WIDTH = 1.F; -constexpr float MIN_ROW_HEIGHT = 0.1F; -constexpr float MAX_ROW_HEIGHT = 1.F; - -// -void SColumnData::add(PHLWINDOW w) { - for (auto& wd : windowDatas) { - wd->windowSize *= (float)windowDatas.size() / (float)(windowDatas.size() + 1); - } - - windowDatas.emplace_back(makeShared(w, self.lock(), 1.F / (float)(windowDatas.size() + 1))); -} - -void SColumnData::add(PHLWINDOW w, int after) { - for (auto& wd : windowDatas) { - wd->windowSize *= (float)windowDatas.size() / (float)(windowDatas.size() + 1); - } - - windowDatas.insert(windowDatas.begin() + after + 1, makeShared(w, self.lock(), 1.F / (float)(windowDatas.size() + 1))); -} - -void SColumnData::add(SP w) { - for (auto& wd : windowDatas) { - wd->windowSize *= (float)windowDatas.size() / (float)(windowDatas.size() + 1); - } - - windowDatas.emplace_back(w); - w->column = self; - w->windowSize = 1.F / (float)(windowDatas.size()); -} - -void SColumnData::add(SP w, int after) { - for (auto& wd : windowDatas) { - wd->windowSize *= (float)windowDatas.size() / (float)(windowDatas.size() + 1); - } - - windowDatas.insert(windowDatas.begin() + after + 1, w); - w->column = self; - w->windowSize = 1.F / (float)(windowDatas.size()); -} - -size_t SColumnData::idx(PHLWINDOW w) { - for (size_t i = 0; i < windowDatas.size(); ++i) { - if (windowDatas[i]->window == w) - return i; - } - return 0; -} - -size_t SColumnData::idxForHeight(float y) { - for (size_t i = 0; i < windowDatas.size(); ++i) { - if (windowDatas[i]->window->m_position.y < y) - continue; - return i - 1; - } - return windowDatas.size() - 1; -} - -void SColumnData::remove(PHLWINDOW w) { - const auto SIZE_BEFORE = windowDatas.size(); - std::erase_if(windowDatas, [&w](const auto& e) { return e->window == w; }); - - if (SIZE_BEFORE == windowDatas.size() && SIZE_BEFORE > 0) - return; - - float newMaxSize = 0.F; - for (auto& wd : windowDatas) { - newMaxSize += wd->windowSize; - } - - for (auto& wd : windowDatas) { - wd->windowSize *= 1.F / newMaxSize; - } - - if (windowDatas.empty() && workspace) - workspace->remove(self.lock()); -} - -void SColumnData::up(SP w) { - for (size_t i = 1; i < windowDatas.size(); ++i) { - if (windowDatas[i] != w) - continue; - - std::swap(windowDatas[i], windowDatas[i - 1]); - break; - } -} - -void SColumnData::down(SP w) { - for (size_t i = 0; i < windowDatas.size() - 1; ++i) { - if (windowDatas[i] != w) - continue; - - std::swap(windowDatas[i], windowDatas[i + 1]); - break; - } -} - -SP SColumnData::next(SP w) { - for (size_t i = 0; i < windowDatas.size() - 1; ++i) { - if (windowDatas[i] != w) - continue; - - return windowDatas[i + 1]; - } - - return nullptr; -} - -SP SColumnData::prev(SP w) { - for (size_t i = 1; i < windowDatas.size(); ++i) { - if (windowDatas[i] != w) - continue; - - return windowDatas[i - 1]; - } - - return nullptr; -} - -bool SColumnData::has(PHLWINDOW w) { - return std::ranges::find_if(windowDatas, [w](const auto& e) { return e->window == w; }) != windowDatas.end(); -} - -SP SWorkspaceData::add() { - static const auto PCOLWIDTH = CConfigValue("plugin:hyprscrolling:column_width"); - auto col = columns.emplace_back(makeShared(self.lock())); - col->self = col; - col->columnWidth = *PCOLWIDTH; - return col; -} - -SP SWorkspaceData::add(int after) { - static const auto PCOLWIDTH = CConfigValue("plugin:hyprscrolling:column_width"); - auto col = makeShared(self.lock()); - col->self = col; - col->columnWidth = *PCOLWIDTH; - columns.insert(columns.begin() + after + 1, col); - return col; -} - -int64_t SWorkspaceData::idx(SP c) { - for (size_t i = 0; i < columns.size(); ++i) { - if (columns[i] == c) - return i; - } - - return -1; -} - -void SWorkspaceData::remove(SP c) { - std::erase(columns, c); -} - -SP SWorkspaceData::next(SP c) { - for (size_t i = 0; i < columns.size(); ++i) { - if (columns[i] != c) - continue; - - if (i == columns.size() - 1) - return nullptr; - - return columns[i + 1]; - } - - return nullptr; -} - -SP SWorkspaceData::prev(SP c) { - for (size_t i = 0; i < columns.size(); ++i) { - if (columns[i] != c) - continue; - - if (i == 0) - return nullptr; - - return columns[i - 1]; - } - - return nullptr; -} - -void SWorkspaceData::centerCol(SP c) { - if (!c) - return; - - static const auto PFSONONE = CConfigValue("plugin:hyprscrolling:fullscreen_on_one_column"); - - PHLMONITOR PMONITOR = workspace->m_monitor.lock(); - double currentLeft = 0; - const auto USABLE = layout->usableAreaFor(PMONITOR); - - for (const auto& COL : columns) { - const double ITEM_WIDTH = *PFSONONE && columns.size() == 1 ? USABLE.w : USABLE.w * COL->columnWidth; - - if (COL != c) - currentLeft += ITEM_WIDTH; - else { - leftOffset = currentLeft - (USABLE.w - ITEM_WIDTH) / 2.F; - return; - } - } -} - -void SWorkspaceData::fitCol(SP c) { - if (!c) - return; - - static const auto PFSONONE = CConfigValue("plugin:hyprscrolling:fullscreen_on_one_column"); - - PHLMONITOR PMONITOR = workspace->m_monitor.lock(); - double currentLeft = 0; - const auto USABLE = layout->usableAreaFor(PMONITOR); - - for (const auto& COL : columns) { - const double ITEM_WIDTH = *PFSONONE && columns.size() == 1 ? USABLE.w : USABLE.w * COL->columnWidth; - - if (COL != c) - currentLeft += ITEM_WIDTH; - else { - leftOffset = std::clamp((double)leftOffset, currentLeft - USABLE.w + ITEM_WIDTH, currentLeft); - return; - } - } -} - -void SWorkspaceData::centerOrFitCol(SP c) { - if (!c) - return; - - static const auto PFITMETHOD = CConfigValue("plugin:hyprscrolling:focus_fit_method"); - - if (*PFITMETHOD == 1) - fitCol(c); - else - centerCol(c); -} - -SP SWorkspaceData::atCenter() { - static const auto PFSONONE = CConfigValue("plugin:hyprscrolling:fullscreen_on_one_column"); - - PHLMONITOR PMONITOR = workspace->m_monitor.lock(); - double currentLeft = leftOffset; - const auto USABLE = layout->usableAreaFor(PMONITOR); - - for (const auto& COL : columns) { - const double ITEM_WIDTH = *PFSONONE && columns.size() == 1 ? USABLE.w : USABLE.w * COL->columnWidth; - - currentLeft += ITEM_WIDTH; - - if (currentLeft >= PMONITOR->m_size.x / 2.0 - 2) - return COL; - } - - return nullptr; -} - -void SWorkspaceData::recalculate(bool forceInstant) { - static const auto PFSONONE = CConfigValue("plugin:hyprscrolling:fullscreen_on_one_column"); - - if (!workspace) { - Log::logger->log(Log::ERR, "[scroller] broken internal state on workspace data"); - return; - } - - const auto MAX_WIDTH = maxWidth(); - - PHLMONITOR PMONITOR = workspace->m_monitor.lock(); - - const CBox USABLE = layout->usableAreaFor(PMONITOR); - - double currentLeft = 0; - const double cameraLeft = MAX_WIDTH < USABLE.w ? std::round((MAX_WIDTH - USABLE.w) / 2.0) : leftOffset; // layout pixels - const auto workAreaPos = layout->workAreaOnWorkspace(PMONITOR->m_activeWorkspace).pos(); - - for (size_t i = 0; i < columns.size(); ++i) { - const auto& COL = columns[i]; - double currentTop = 0.0; - const double ITEM_WIDTH = *PFSONONE && columns.size() == 1 ? USABLE.w : USABLE.w * COL->columnWidth; - - for (const auto& WINDOW : COL->windowDatas) { - WINDOW->layoutBox = CBox{currentLeft, currentTop, ITEM_WIDTH, WINDOW->windowSize * USABLE.h}.translate(workAreaPos + Vector2D{-cameraLeft, 0.0}); - - currentTop += WINDOW->windowSize * USABLE.h; - - layout->applyNodeDataToWindow(WINDOW, forceInstant, i != columns.size() - 1, i != 0); - } - - currentLeft += ITEM_WIDTH; - if (currentLeft == USABLE.width) - currentLeft++; // avoid ffm from "grabbing" the window on the right - } -} - -double SWorkspaceData::maxWidth() { - static const auto PFSONONE = CConfigValue("plugin:hyprscrolling:fullscreen_on_one_column"); - - PHLMONITOR PMONITOR = workspace->m_monitor.lock(); - double currentLeft = 0; - const auto USABLE = layout->usableAreaFor(PMONITOR); - - for (const auto& COL : columns) { - const double ITEM_WIDTH = *PFSONONE && columns.size() == 1 ? USABLE.w : USABLE.w * COL->columnWidth; - - currentLeft += ITEM_WIDTH; - } - - return currentLeft; -} - -bool SWorkspaceData::visible(SP c) { - const auto USABLE = layout->usableAreaFor(workspace->m_monitor.lock()); - float totalLeft = 0; - for (const auto& col : columns) { - if (col == c) { - const float colLeft = totalLeft; - const float colRight = totalLeft + col->columnWidth * USABLE.w; - const float viewLeft = leftOffset; - const float viewRight = leftOffset + USABLE.w; - return colLeft < viewRight && viewLeft < colRight; - } - - totalLeft += col->columnWidth * USABLE.w; - } - - return false; -} - -void CScrollingLayout::applyNodeDataToWindow(SP data, bool force, bool hasWindowsRight, bool hasWindowsLeft) { - PHLMONITOR PMONITOR; - PHLWORKSPACE PWORKSPACE; - - if (!data || !data->column || !data->column->workspace) { - if (!data->overrideWorkspace) { - Log::logger->log(Log::ERR, "[scroller] broken internal state on workspace (1)"); - return; - } - - PMONITOR = data->overrideWorkspace->m_monitor.lock(); - PWORKSPACE = data->overrideWorkspace.lock(); - } else { - PMONITOR = data->column->workspace->workspace->m_monitor.lock(); - PWORKSPACE = data->column->workspace->workspace.lock(); - } - - if (!PMONITOR || !PWORKSPACE) { - Log::logger->log(Log::ERR, "[scroller] broken internal state on workspace (2)"); - return; - } - - // for gaps outer - const auto WORKAREA = workAreaOnWorkspace(PWORKSPACE); - const bool DISPLAYLEFT = !hasWindowsLeft; - const bool DISPLAYRIGHT = !hasWindowsRight; - const bool DISPLAYTOP = STICKS(data->layoutBox.y, WORKAREA.y); - const bool DISPLAYBOTTOM = STICKS(data->layoutBox.y + data->layoutBox.h, WORKAREA.y + WORKAREA.h); - - const auto PWINDOW = data->window.lock(); - // get specific gaps and rules for this workspace, - // if user specified them in config - const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE); - - if (!validMapped(PWINDOW)) { - Log::logger->log(Log::ERR, "Node {} holding invalid {}!!", (uintptr_t)data.get(), PWINDOW); - onWindowRemovedTiling(PWINDOW); - return; - } - - if (PWINDOW->isFullscreen() && !data->ignoreFullscreenChecks) - return; - - PWINDOW->m_ruleApplicator->resetProps(Desktop::Rule::RULE_PROP_ALL, Desktop::Types::PRIORITY_LAYOUT); - PWINDOW->updateWindowData(); - - static auto PGAPSINDATA = CConfigValue("general:gaps_in"); - auto* const PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); - - auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN); - CBox nodeBox = data->layoutBox; - nodeBox.round(); - - PWINDOW->m_size = nodeBox.size(); - PWINDOW->m_position = nodeBox.pos(); - - PWINDOW->updateWindowDecos(); - - auto calcPos = PWINDOW->m_position; - auto calcSize = PWINDOW->m_size; - - const auto OFFSETTOPLEFT = Vector2D((double)(DISPLAYLEFT ? 0 : gapsIn.m_left), (double)(DISPLAYTOP ? 0 : gapsIn.m_top)); - - const auto OFFSETBOTTOMRIGHT = Vector2D((double)(DISPLAYRIGHT ? 0 : gapsIn.m_right), (double)(DISPLAYBOTTOM ? 0 : gapsIn.m_bottom)); - - calcPos = calcPos + OFFSETTOPLEFT; - calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT; - - if (PWINDOW->m_isPseudotiled) { - // Calculate pseudo - float scale = 1; - - // adjust if doesnt fit - if (PWINDOW->m_pseudoSize.x > calcSize.x || PWINDOW->m_pseudoSize.y > calcSize.y) { - if (PWINDOW->m_pseudoSize.x > calcSize.x) { - scale = calcSize.x / PWINDOW->m_pseudoSize.x; - } - - if (PWINDOW->m_pseudoSize.y * scale > calcSize.y) { - scale = calcSize.y / PWINDOW->m_pseudoSize.y; - } - - auto DELTA = calcSize - PWINDOW->m_pseudoSize * scale; - calcSize = PWINDOW->m_pseudoSize * scale; - calcPos = calcPos + DELTA / 2.f; // center - } else { - auto DELTA = calcSize - PWINDOW->m_pseudoSize; - calcPos = calcPos + DELTA / 2.f; // center - calcSize = PWINDOW->m_pseudoSize; - } - } - - const auto RESERVED = PWINDOW->getFullWindowReservedArea(); - calcPos = calcPos + RESERVED.topLeft; - calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight); - - if (PWINDOW->onSpecialWorkspace() && !PWINDOW->isFullscreen()) { - // if special, we adjust the coords a bit - static auto PSCALEFACTOR = CConfigValue("dwindle:special_scale_factor"); - - CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR}; - wb.round(); // avoid rounding mess - - *PWINDOW->m_realPosition = wb.pos(); - *PWINDOW->m_realSize = wb.size(); - } else { - CBox wb = {calcPos, calcSize}; - wb.round(); // avoid rounding mess - - *PWINDOW->m_realSize = wb.size(); - *PWINDOW->m_realPosition = wb.pos(); - } - - if (force) { - g_pHyprRenderer->damageWindow(PWINDOW); - - PWINDOW->m_realPosition->warp(); - PWINDOW->m_realSize->warp(); - - g_pHyprRenderer->damageWindow(PWINDOW); - } - - PWINDOW->updateWindowDecos(); -} - -void CScrollingLayout::onEnable() { - static const auto PCONFWIDTHS = CConfigValue("plugin:hyprscrolling:explicit_column_widths"); - - m_configCallback = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) { - // bitch ass - m_config.configuredWidths.clear(); - - CConstVarList widths(*PCONFWIDTHS, 0, ','); - for (auto& w : widths) { - try { - m_config.configuredWidths.emplace_back(std::stof(std::string{w})); - } catch (...) { Log::logger->log(Log::ERR, "scrolling: Failed to parse width {} as float", w); } - } - if (m_config.configuredWidths.empty()) - m_config.configuredWidths = {0.333, 0.5, 0.667, 1.0}; - }); - - m_focusCallback = g_pHookSystem->hookDynamic("activeWindow", [this](void* hk, SCallbackInfo& info, std::any param) { - const auto PWINDOW = std::any_cast(param); - - if (!PWINDOW) - return; - - static const auto PFOLLOW_FOCUS = CConfigValue("plugin:hyprscrolling:follow_focus"); - - if (!*PFOLLOW_FOCUS) - return; - - if (!PWINDOW->m_workspace->isVisible()) - return; - - const auto DATA = dataFor(PWINDOW->m_workspace); - const auto WINDOWDATA = dataFor(PWINDOW); - - if (!DATA || !WINDOWDATA) - return; - - static const auto PFOLLOW_DEBOUNCE_MS = CConfigValue("plugin:hyprscrolling:follow_debounce_ms"); - static CTimer debounceTimer; - if (debounceTimer.getMillis() < *PFOLLOW_DEBOUNCE_MS) - return; - static const auto PFITMETHOD = CConfigValue("plugin:hyprscrolling:focus_fit_method"); - if (*PFITMETHOD == 1) - DATA->fitCol(WINDOWDATA->column.lock()); - else - DATA->centerCol(WINDOWDATA->column.lock()); - DATA->recalculate(); - debounceTimer.reset(); - }); - - for (auto const& w : g_pCompositor->m_windows) { - if (w->m_isFloating || !w->m_isMapped || w->isHidden()) - continue; - - onWindowCreatedTiling(w); - } -} - -void CScrollingLayout::onDisable() { - m_workspaceDatas.clear(); - m_configCallback.reset(); -} - -void CScrollingLayout::onWindowCreatedTiling(PHLWINDOW window, eDirection direction) { - if (m_columnMoveState.isMovingColumn && window->m_workspace->m_id == m_columnMoveState.targetWorkspaceID) - return; - - auto workspaceData = dataFor(window->m_workspace); - - if (!workspaceData) { - Log::logger->log(Log::DEBUG, "[scrolling] No workspace data yet, creating"); - workspaceData = m_workspaceDatas.emplace_back(makeShared(window->m_workspace, this)); - workspaceData->self = workspaceData; - } - - auto droppingOn = Desktop::focusState()->window(); - - if (droppingOn == window) - droppingOn = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS); - - SP droppingData = droppingOn ? dataFor(droppingOn) : nullptr; - SP droppingColumn = droppingData ? droppingData->column.lock() : nullptr; - - Log::logger->log(Log::DEBUG, "[scrolling] new window {:x}, droppingColumn: {:x}, columns before: {}", (uintptr_t)window.get(), (uintptr_t)droppingColumn.get(), - workspaceData->columns.size()); - - if (!droppingColumn) { - auto col = workspaceData->add(); - col->add(window); - workspaceData->fitCol(col); - } else { - if (window->m_draggingTiled) { - if (droppingOn) { - const auto IDX = droppingColumn->idx(droppingOn); - const auto TOP = droppingOn->getWindowIdealBoundingBoxIgnoreReserved().middle().y > g_pInputManager->getMouseCoordsInternal().y; - droppingColumn->add(window, TOP ? (IDX == 0 ? -1 : IDX - 1) : (IDX)); - } else - droppingColumn->add(window); - workspaceData->fitCol(droppingColumn); - } else { - auto idx = workspaceData->idx(droppingColumn); - auto col = idx == -1 ? workspaceData->add() : workspaceData->add(idx); - col->add(window); - workspaceData->fitCol(col); - } - } - - workspaceData->recalculate(); -} - -void CScrollingLayout::onWindowRemovedTiling(PHLWINDOW window) { - const auto DATA = dataFor(window); - - if (!DATA) - return; - - const auto WS = DATA->column->workspace.lock(); - - if (!WS->next(DATA->column.lock())) { - // move the view if this is the last column - const auto USABLE = usableAreaFor(window->m_monitor.lock()); - WS->leftOffset -= USABLE.w * DATA->column->columnWidth; - } - - DATA->column->remove(window); - - WS->recalculate(); - - if (!DATA->column) { - // column got removed, let's ensure we don't leave any cringe extra space - const auto USABLE = usableAreaFor(window->m_monitor.lock()); - WS->leftOffset = std::clamp((double)WS->leftOffset, 0.0, std::max(WS->maxWidth() - USABLE.w, 1.0)); - } -} - -bool CScrollingLayout::isWindowTiled(PHLWINDOW window) { - const auto DATA = dataFor(window); - - return DATA; -} - -void CScrollingLayout::recalculateMonitor(const MONITORID& id) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(id); - if (!PMONITOR || !PMONITOR->m_activeWorkspace) - return; - - const auto DATA = dataFor(PMONITOR->m_activeWorkspace); - - if (!DATA) - return; - - DATA->recalculate(); -} - -void CScrollingLayout::recalculateWindow(PHLWINDOW window) { - if (!window->m_workspace) - return; - - const auto DATA = dataFor(window->m_workspace); - - if (!DATA) - return; - - DATA->recalculate(); -} - -void CScrollingLayout::onBeginDragWindow() { - IHyprLayout::onBeginDragWindow(); -} - -void CScrollingLayout::resizeActiveWindow(const Vector2D& delta, eRectCorner corner, PHLWINDOW pWindow) { - const auto PWINDOW = pWindow ? pWindow : Desktop::focusState()->window(); - Vector2D modDelta = delta; - - if (!validMapped(PWINDOW)) - return; - - const auto DATA = dataFor(PWINDOW); - - if (!DATA) { - *PWINDOW->m_realSize = (PWINDOW->m_realSize->goal() + delta) - .clamp(PWINDOW->m_ruleApplicator->minSize().valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), - PWINDOW->m_ruleApplicator->maxSize().valueOr(Vector2D{INFINITY, INFINITY})); - PWINDOW->updateWindowDecos(); - return; - } - - if (!DATA->column || !DATA->column->workspace || !DATA->column->workspace->workspace || !DATA->column->workspace->workspace->m_monitor) - return; - - const auto USABLE = usableAreaFor(DATA->column->workspace->workspace->m_monitor.lock()); - const auto DELTA_AS_PERC = delta / USABLE.size(); - - const auto CURR_COLUMN = DATA->column.lock(); - const auto NEXT_COLUMN = DATA->column->workspace->next(CURR_COLUMN); - const auto PREV_COLUMN = DATA->column->workspace->prev(CURR_COLUMN); - - switch (corner) { - case CORNER_BOTTOMLEFT: - case CORNER_TOPLEFT: { - if (!PREV_COLUMN) - break; - - PREV_COLUMN->columnWidth = std::clamp(PREV_COLUMN->columnWidth + (float)DELTA_AS_PERC.x, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); - CURR_COLUMN->columnWidth = std::clamp(CURR_COLUMN->columnWidth - (float)DELTA_AS_PERC.x, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); - break; - } - case CORNER_BOTTOMRIGHT: - case CORNER_TOPRIGHT: { - if (!NEXT_COLUMN) - break; - - NEXT_COLUMN->columnWidth = std::clamp(NEXT_COLUMN->columnWidth - (float)DELTA_AS_PERC.x, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); - CURR_COLUMN->columnWidth = std::clamp(CURR_COLUMN->columnWidth + (float)DELTA_AS_PERC.x, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); - break; - } - - default: break; - } - - if (DATA->column->windowDatas.size() > 1) { - const auto CURR_WD = DATA; - const auto NEXT_WD = DATA->column->next(DATA); - const auto PREV_WD = DATA->column->prev(DATA); - if (corner == CORNER_NONE) { - if (!PREV_WD) - corner = CORNER_BOTTOMRIGHT; - else { - corner = CORNER_TOPRIGHT; - modDelta.y *= -1.0f; - } - } - - switch (corner) { - case CORNER_BOTTOMLEFT: - case CORNER_BOTTOMRIGHT: { - if (!NEXT_WD) - break; - - if (NEXT_WD->windowSize <= MIN_ROW_HEIGHT && delta.y >= 0) - break; - - float adjust = std::clamp((float)(delta.y / USABLE.h), (-CURR_WD->windowSize + MIN_ROW_HEIGHT), (NEXT_WD->windowSize - MIN_ROW_HEIGHT)); - - NEXT_WD->windowSize = std::clamp(NEXT_WD->windowSize - adjust, MIN_ROW_HEIGHT, MAX_ROW_HEIGHT); - CURR_WD->windowSize = std::clamp(CURR_WD->windowSize + adjust, MIN_ROW_HEIGHT, MAX_ROW_HEIGHT); - break; - } - case CORNER_TOPLEFT: - case CORNER_TOPRIGHT: { - if (!PREV_WD) - break; - - if (PREV_WD->windowSize <= MIN_ROW_HEIGHT && modDelta.y <= 0 || CURR_WD->windowSize <= MIN_ROW_HEIGHT && delta.y >= 0) - break; - - float adjust = std::clamp((float)(modDelta.y / USABLE.h), -(PREV_WD->windowSize - MIN_ROW_HEIGHT), (CURR_WD->windowSize - MIN_ROW_HEIGHT)); - - PREV_WD->windowSize = std::clamp(PREV_WD->windowSize + adjust, MIN_ROW_HEIGHT, MAX_ROW_HEIGHT); - CURR_WD->windowSize = std::clamp(CURR_WD->windowSize - adjust, MIN_ROW_HEIGHT, MAX_ROW_HEIGHT); - break; - } - - default: break; - } - } - - DATA->column->workspace->recalculate(true); -} - -void CScrollingLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) { - const auto PMONITOR = pWindow->m_monitor.lock(); - const auto PWORKSPACE = pWindow->m_workspace; - - // save position and size if floating - if (pWindow->m_isFloating && CURRENT_EFFECTIVE_MODE == FSMODE_NONE) { - pWindow->m_lastFloatingSize = pWindow->m_realSize->goal(); - pWindow->m_lastFloatingPosition = pWindow->m_realPosition->goal(); - pWindow->m_position = pWindow->m_realPosition->goal(); - pWindow->m_size = pWindow->m_realSize->goal(); - } - - const auto PNODE = dataFor(pWindow); - - if (EFFECTIVE_MODE == FSMODE_NONE) { - // if it got its fullscreen disabled, set back its node if it had one - - if (PNODE) - applyNodeDataToWindow(PNODE, false, false, false); - else { - // get back its' dimensions from position and size - *pWindow->m_realPosition = pWindow->m_lastFloatingPosition; - *pWindow->m_realSize = pWindow->m_lastFloatingSize; - - pWindow->m_ruleApplicator->resetProps(Desktop::Rule::RULE_PROP_ALL, Desktop::Types::PRIORITY_LAYOUT); - pWindow->updateWindowData(); - } - } else { - // apply new pos and size being monitors' box - if (EFFECTIVE_MODE == FSMODE_FULLSCREEN) { - *pWindow->m_realPosition = PMONITOR->m_position; - *pWindow->m_realSize = PMONITOR->m_size; - } else { - // This is a massive hack. - // We make a fake "only" node and apply - // To keep consistent with the settings without C+P code - - SP fakeNode = makeShared(pWindow, nullptr); - fakeNode->window = pWindow; - fakeNode->layoutBox = workAreaOnWorkspace(PWORKSPACE); - pWindow->m_size = fakeNode->layoutBox.size(); - fakeNode->ignoreFullscreenChecks = true; - fakeNode->overrideWorkspace = pWindow->m_workspace; - - applyNodeDataToWindow(fakeNode, false, false, false); - } - } - - g_pCompositor->changeWindowZOrder(pWindow, true); -} - -void CScrollingLayout::focusWindowUpdate(PHLWINDOW pWindow) { - if (!validMapped(pWindow)) { - Desktop::focusState()->fullWindowFocus(nullptr); - return; - } - Desktop::focusState()->fullWindowFocus(pWindow); - const auto WINDOWDATA = dataFor(pWindow); - if (WINDOWDATA) { - if (auto col = WINDOWDATA->column.lock()) - col->lastFocusedWindow = WINDOWDATA; - } -} - -SP CScrollingLayout::findBestNeighbor(SP pCurrent, SP pTargetCol) { - if (!pCurrent || !pTargetCol || pTargetCol->windowDatas.empty()) - return nullptr; - - const double currentTop = pCurrent->layoutBox.y; - const double currentBottom = pCurrent->layoutBox.y + pCurrent->layoutBox.h; - std::vector> overlappingWindows; - for (const auto& candidate : pTargetCol->windowDatas) { - const double candidateTop = candidate->layoutBox.y; - const double candidateBottom = candidate->layoutBox.y + candidate->layoutBox.h; - const bool overlaps = (candidateTop < currentBottom) && (candidateBottom > currentTop); - - if (overlaps) - overlappingWindows.emplace_back(candidate); - } - if (!overlappingWindows.empty()) { - auto lastFocused = pTargetCol->lastFocusedWindow.lock(); - - if (lastFocused) { - auto it = std::ranges::find(overlappingWindows, lastFocused); - if (it != overlappingWindows.end()) - return lastFocused; - } - - auto topmost = std::ranges::min_element(overlappingWindows, std::less<>{}, [](const SP& w) { return w->layoutBox.y; }); - return *topmost; - } - if (!pTargetCol->windowDatas.empty()) - return pTargetCol->windowDatas.front(); - return nullptr; -} - -std::any CScrollingLayout::layoutMessage(SLayoutMessageHeader header, std::string message) { - static auto centerOrFit = [](const SP WS, const SP COL) -> void { - static const auto PFITMETHOD = CConfigValue("plugin:hyprscrolling:focus_fit_method"); - if (*PFITMETHOD == 1) - WS->fitCol(COL); - else - WS->centerCol(COL); - }; - - const auto ARGS = CVarList(message, 0, ' '); - if (ARGS[0] == "move") { - const auto DATA = currentWorkspaceData(); - if (!DATA) - return {}; - - if (ARGS[1] == "+col" || ARGS[1] == "col") { - const auto WDATA = dataFor(Desktop::focusState()->window()); - if (!WDATA) - return {}; - - const auto COL = DATA->next(WDATA->column.lock()); - if (!COL) { - // move to max - DATA->leftOffset = DATA->maxWidth(); - DATA->recalculate(); - focusWindowUpdate(nullptr); - return {}; - } - - centerOrFit(DATA, COL); - DATA->recalculate(); - - focusWindowUpdate(COL->windowDatas.front()->window.lock()); - g_pCompositor->warpCursorTo(COL->windowDatas.front()->window.lock()->middle()); - - return {}; - } else if (ARGS[1] == "-col") { - const auto WDATA = dataFor(Desktop::focusState()->window()); - if (!WDATA) { - if (DATA->columns.size() > 0) { - DATA->centerCol(DATA->columns.back()); - DATA->recalculate(); - focusWindowUpdate((DATA->columns.back()->windowDatas.back())->window.lock()); - g_pCompositor->warpCursorTo((DATA->columns.back()->windowDatas.back())->window.lock()->middle()); - } - - return {}; - } - - const auto COL = DATA->prev(WDATA->column.lock()); - if (!COL) - return {}; - - centerOrFit(DATA, COL); - DATA->recalculate(); - - focusWindowUpdate(COL->windowDatas.back()->window.lock()); - g_pCompositor->warpCursorTo(COL->windowDatas.front()->window.lock()->middle()); - - return {}; - } - - const auto PLUSMINUS = getPlusMinusKeywordResult(ARGS[1], 0); - - if (!PLUSMINUS.has_value()) - return {}; - - DATA->leftOffset -= *PLUSMINUS; - DATA->recalculate(); - - const auto ATCENTER = DATA->atCenter(); - - focusWindowUpdate(ATCENTER ? (*ATCENTER->windowDatas.begin())->window.lock() : nullptr); - } else if (ARGS[0] == "colresize") { - const auto WDATA = dataFor(Desktop::focusState()->window()); - - if (!WDATA) - return {}; - - if (ARGS[1] == "all") { - float abs = 0; - try { - abs = std::stof(ARGS[2]); - } catch (...) { return {}; } - - for (const auto& c : WDATA->column->workspace->columns) { - c->columnWidth = abs; - } - - WDATA->column->workspace->recalculate(); - return {}; - } - - CScopeGuard x([WDATA] { - WDATA->column->columnWidth = std::clamp(WDATA->column->columnWidth, MIN_COLUMN_WIDTH, MAX_COLUMN_WIDTH); - WDATA->column->workspace->centerOrFitCol(WDATA->column.lock()); - WDATA->column->workspace->recalculate(); - }); - - if (ARGS[1][0] == '+' || ARGS[1][0] == '-') { - if (ARGS[1] == "+conf") { - for (size_t i = 0; i < m_config.configuredWidths.size(); ++i) { - if (m_config.configuredWidths[i] > WDATA->column->columnWidth) { - WDATA->column->columnWidth = m_config.configuredWidths[i]; - break; - } - - if (i == m_config.configuredWidths.size() - 1) - WDATA->column->columnWidth = m_config.configuredWidths[0]; - } - - return {}; - } else if (ARGS[1] == "-conf") { - for (size_t i = m_config.configuredWidths.size() - 1;; --i) { - if (m_config.configuredWidths[i] < WDATA->column->columnWidth) { - WDATA->column->columnWidth = m_config.configuredWidths[i]; - break; - } - - if (i == 0) { - WDATA->column->columnWidth = m_config.configuredWidths.back(); - break; - } - } - - return {}; - } - - const auto PLUSMINUS = getPlusMinusKeywordResult(ARGS[1], 0); - - if (!PLUSMINUS.has_value()) - return {}; - - WDATA->column->columnWidth += *PLUSMINUS; - } else { - float abs = 0; - try { - abs = std::stof(ARGS[1]); - } catch (...) { return {}; } - - WDATA->column->columnWidth = abs; - } - } else if (ARGS[0] == "movewindowto") { - moveWindowTo(Desktop::focusState()->window(), ARGS[1], false); - } else if (ARGS[0] == "fit") { - - if (ARGS[1] == "active") { - // fit the current column to 1.F - const auto WDATA = dataFor(Desktop::focusState()->window()); - const auto WORKDATA = dataFor(Desktop::focusState()->window()->m_workspace); - - if (!WDATA || !WORKDATA || WORKDATA->columns.size() == 0) - return {}; - - const auto USABLE = usableAreaFor(WORKDATA->workspace->m_monitor.lock()); - - WDATA->column->columnWidth = 1.F; - - WORKDATA->leftOffset = 0; - for (size_t i = 0; i < WORKDATA->columns.size(); ++i) { - if (WORKDATA->columns[i]->has(Desktop::focusState()->window())) - break; - - WORKDATA->leftOffset += USABLE.w * WORKDATA->columns[i]->columnWidth; - } - - WDATA->column->workspace->recalculate(); - } else if (ARGS[1] == "all") { - // fit all columns on screen - const auto WDATA = dataFor(Desktop::focusState()->window()->m_workspace); - - if (!WDATA || WDATA->columns.size() == 0) - return {}; - - const size_t LEN = WDATA->columns.size(); - for (const auto& c : WDATA->columns) { - c->columnWidth = 1.F / (float)LEN; - } - - WDATA->recalculate(); - } else if (ARGS[1] == "toend") { - // fit all columns on screen that start from the current and end on the last - const auto WDATA = dataFor(Desktop::focusState()->window()->m_workspace); - - if (!WDATA || WDATA->columns.size() == 0) - return {}; - - bool begun = false; - size_t foundAt = 0; - for (size_t i = 0; i < WDATA->columns.size(); ++i) { - if (!begun && !WDATA->columns[i]->has(Desktop::focusState()->window())) - continue; - - if (!begun) { - begun = true; - foundAt = i; - } - - WDATA->columns[i]->columnWidth = 1.F / (float)(WDATA->columns.size() - i); - } - - if (!begun) - return {}; - - const auto USABLE = usableAreaFor(WDATA->workspace->m_monitor.lock()); - - WDATA->leftOffset = 0; - for (size_t i = 0; i < foundAt; ++i) { - WDATA->leftOffset += USABLE.w * WDATA->columns[i]->columnWidth; - } - - WDATA->recalculate(); - } else if (ARGS[1] == "tobeg") { - // fit all columns on screen that start from the current and end on the last - const auto WDATA = dataFor(Desktop::focusState()->window()->m_workspace); - - if (!WDATA || WDATA->columns.size() == 0) - return {}; - - bool begun = false; - size_t foundAt = 0; - for (int64_t i = (int64_t)WDATA->columns.size() - 1; i >= 0; --i) { - if (!begun && !WDATA->columns[i]->has(Desktop::focusState()->window())) - continue; - - if (!begun) { - begun = true; - foundAt = i; - } - - WDATA->columns[i]->columnWidth = 1.F / (float)(foundAt + 1); - } - - if (!begun) - return {}; - - WDATA->leftOffset = 0; - - WDATA->recalculate(); - } else if (ARGS[1] == "visible") { - // fit all columns on screen that start from the current and end on the last - const auto WDATA = dataFor(Desktop::focusState()->window()->m_workspace); - - if (!WDATA || WDATA->columns.size() == 0) - return {}; - - bool begun = false; - size_t foundAt = 0; - std::vector> visible; - for (size_t i = 0; i < WDATA->columns.size(); ++i) { - if (!begun && !WDATA->visible(WDATA->columns[i])) - continue; - - if (!begun) { - begun = true; - foundAt = i; - } - - if (!WDATA->visible(WDATA->columns[i])) - break; - - visible.emplace_back(WDATA->columns[i]); - } - - if (!begun) - return {}; - - WDATA->leftOffset = 0; - - if (foundAt != 0) { - const auto USABLE = usableAreaFor(WDATA->workspace->m_monitor.lock()); - - for (size_t i = 0; i < foundAt; ++i) { - WDATA->leftOffset += USABLE.w * WDATA->columns[i]->columnWidth; - } - } - - for (const auto& v : visible) { - v->columnWidth = 1.F / (float)visible.size(); - } - - WDATA->recalculate(); - } - } else if (ARGS[0] == "focus") { - const auto WDATA = dataFor(Desktop::focusState()->window()); - static const auto PNOFALLBACK = CConfigValue("general:no_focus_fallback"); - - if (!WDATA || ARGS[1].empty()) - return {}; - - switch (ARGS[1][0]) { - case 'u': - case 't': { - auto PREV = WDATA->column->prev(WDATA); - if (!PREV) { - if (*PNOFALLBACK) - break; - else - PREV = WDATA->column->windowDatas.back(); - } - - focusWindowUpdate(PREV->window.lock()); - g_pCompositor->warpCursorTo(PREV->window.lock()->middle()); - break; - } - - case 'b': - case 'd': { - auto NEXT = WDATA->column->next(WDATA); - if (!NEXT) { - if (*PNOFALLBACK) - break; - else - NEXT = WDATA->column->windowDatas.front(); - } - - focusWindowUpdate(NEXT->window.lock()); - g_pCompositor->warpCursorTo(NEXT->window.lock()->middle()); - break; - } - - case 'l': { - auto PREV = WDATA->column->workspace->prev(WDATA->column.lock()); - if (!PREV) { - if (*PNOFALLBACK) { - centerOrFit(WDATA->column->workspace.lock(), WDATA->column.lock()); - WDATA->column->workspace->recalculate(); - g_pCompositor->warpCursorTo(WDATA->window.lock()->middle()); - break; - } else - PREV = WDATA->column->workspace->columns.back(); - } - - auto pTargetWindowData = findBestNeighbor(WDATA, PREV); - if (pTargetWindowData) { - focusWindowUpdate(pTargetWindowData->window.lock()); - centerOrFit(WDATA->column->workspace.lock(), PREV); - WDATA->column->workspace->recalculate(); - g_pCompositor->warpCursorTo(pTargetWindowData->window.lock()->middle()); - } - break; - } - - case 'r': { - auto NEXT = WDATA->column->workspace->next(WDATA->column.lock()); - if (!NEXT) { - if (*PNOFALLBACK) { - centerOrFit(WDATA->column->workspace.lock(), WDATA->column.lock()); - WDATA->column->workspace->recalculate(); - g_pCompositor->warpCursorTo(WDATA->window.lock()->middle()); - break; - } else - NEXT = WDATA->column->workspace->columns.front(); - } - - auto pTargetWindowData = findBestNeighbor(WDATA, NEXT); - if (pTargetWindowData) { - focusWindowUpdate(pTargetWindowData->window.lock()); - centerOrFit(WDATA->column->workspace.lock(), NEXT); - WDATA->column->workspace->recalculate(); - g_pCompositor->warpCursorTo(pTargetWindowData->window.lock()->middle()); - } - break; - } - - default: return {}; - } - } else if (ARGS[0] == "promote") { - const auto WDATA = dataFor(Desktop::focusState()->window()); - - if (!WDATA) - return {}; - - auto idx = WDATA->column->workspace->idx(WDATA->column.lock()); - auto col = idx == -1 ? WDATA->column->workspace->add() : WDATA->column->workspace->add(idx); - - WDATA->column->remove(WDATA->window.lock()); - - col->add(WDATA); - - WDATA->column->workspace->recalculate(); - } else if (ARGS[0] == "swapcol") { - if (ARGS.size() < 2) - return {}; - - const auto WDATA = dataFor(Desktop::focusState()->window()); - if (!WDATA) - return {}; - - const auto CURRENT_COL = WDATA->column.lock(); - if (!CURRENT_COL) - return {}; - - const auto WS_DATA = CURRENT_COL->workspace.lock(); - if (!WS_DATA || WS_DATA->columns.size() < 2) - return {}; - - const int64_t current_idx = WS_DATA->idx(CURRENT_COL); - const size_t col_count = WS_DATA->columns.size(); - - if (current_idx == -1) - return {}; - - const std::string& direction = ARGS[1]; - int64_t target_idx = -1; - - if (direction == "l") - target_idx = (current_idx == 0) ? (col_count - 1) : (current_idx - 1); - else if (direction == "r") - target_idx = (current_idx == (int64_t)col_count - 1) ? 0 : (current_idx + 1); - else - return {}; - - std::swap(WS_DATA->columns[current_idx], WS_DATA->columns[target_idx]); - WS_DATA->centerOrFitCol(CURRENT_COL); - WS_DATA->recalculate(); - } else if (ARGS[0] == "movecoltoworkspace") { - if (ARGS.size() < 2) - return {}; - - const auto WDATA = dataFor(Desktop::focusState()->window()); - if (!WDATA) - return {}; - - const auto CURRENT_COL = WDATA->column.lock(); - if (!CURRENT_COL) - return {}; - - const auto SOURCE_WS_DATA = CURRENT_COL->workspace.lock(); - if (!SOURCE_WS_DATA) - return {}; - - const auto PMONITOR = Desktop::focusState()->monitor(); - if (!PMONITOR) - return {}; - - PHLWORKSPACE PWORKSPACE = nullptr; - const std::string& arg = ARGS[1]; - - if (arg.starts_with("+") || arg.starts_with("-")) { - try { - const int offset = std::stoi(arg); - const int currentWorkspaceID = WDATA->window->m_workspace->m_id; - const int targetWorkspaceID = currentWorkspaceID + offset; - - if (targetWorkspaceID < 1) - return {}; - - PWORKSPACE = g_pCompositor->getWorkspaceByID(targetWorkspaceID); - if (!PWORKSPACE) - PWORKSPACE = g_pCompositor->createNewWorkspace(targetWorkspaceID, PMONITOR->m_id); - } catch (...) { return {}; } - } else if (arg == "special") { - const int SPECIAL_WORKSPACE_ID = -99; - PWORKSPACE = g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID); - if (!PWORKSPACE) - PWORKSPACE = g_pCompositor->createNewWorkspace(SPECIAL_WORKSPACE_ID, PMONITOR->m_id, "special"); - } else { - PWORKSPACE = g_pCompositor->getWorkspaceByString(arg); - if (!PWORKSPACE) { - try { - const int workspaceID = std::stoi(arg); - PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceID); - if (!PWORKSPACE) - PWORKSPACE = g_pCompositor->createNewWorkspace(workspaceID, PMONITOR->m_id); - } catch (const std::invalid_argument&) { PWORKSPACE = g_pCompositor->createNewWorkspace(0, PMONITOR->m_id, arg); } catch (const std::out_of_range&) { - return {}; - } - } - } - if (!PWORKSPACE) - return {}; - - if (PWORKSPACE == WDATA->window->m_workspace) - return {}; - - auto targetWorkspaceData = dataFor(PWORKSPACE); - if (!targetWorkspaceData) { - targetWorkspaceData = m_workspaceDatas.emplace_back(makeShared(PWORKSPACE, this)); - targetWorkspaceData->self = targetWorkspaceData; - } - - const auto NEW_COL = targetWorkspaceData->add(); - - NEW_COL->columnWidth = CURRENT_COL->columnWidth; - NEW_COL->windowDatas = CURRENT_COL->windowDatas; - - for (const auto& wd : NEW_COL->windowDatas) { - wd->column = NEW_COL; - } - - std::vector windowsToMove; - for (const auto& wd : CURRENT_COL->windowDatas) { - windowsToMove.push_back(wd->window.lock()); - } - - CURRENT_COL->windowDatas.clear(); - SOURCE_WS_DATA->remove(CURRENT_COL); - - CScopeGuard sg([this]() { - m_columnMoveState.isMovingColumn = false; - m_columnMoveState.targetWorkspaceID = -1; - - for (auto& ws : m_workspaceDatas) { - ws->recalculate(); - } - }); - - m_columnMoveState.isMovingColumn = true; - m_columnMoveState.targetWorkspaceID = PWORKSPACE->m_id; - - for (const auto& win : windowsToMove) { - g_pCompositor->moveWindowToWorkspaceSafe(win, PWORKSPACE); - } - - Desktop::focusState()->fullWindowFocus(windowsToMove.front()); - g_pCompositor->warpCursorTo(windowsToMove.front()->middle()); - } else if (ARGS[0] == "togglefit") { - static const auto PFITMETHOD = CConfigValue("plugin:hyprscrolling:focus_fit_method"); - auto& fitMethod = *PFITMETHOD.ptr(); - const int toggled = fitMethod ^ 1; - - fitMethod = toggled; - - const auto focusedData = dataFor(Desktop::focusState()->window()); - static const auto PFSONONE = CConfigValue("plugin:hyprscrolling:fullscreen_on_one_column"); - - for (const auto& ws : m_workspaceDatas) { - if (!ws || ws->columns.empty()) - continue; - - const auto monitor = ws->workspace->m_monitor.lock(); - if (!monitor) - continue; - - const auto USABLE = usableAreaFor(monitor); - - const auto focusedColumn = (focusedData && focusedData->column && focusedData->column->workspace.lock() == ws) ? focusedData->column.lock() : nullptr; - - const auto fallbackColumn = ws->atCenter(); - - if (toggled == 1) { - const auto columnToFit = focusedColumn ? focusedColumn : fallbackColumn; - if (!columnToFit) - continue; - - double currentLeft = 0.0; - for (const auto& col : ws->columns) { - const double itemWidth = *PFSONONE && ws->columns.size() == 1 ? USABLE.w : USABLE.w * col->columnWidth; - - if (col == columnToFit) { - const double colLeft = currentLeft; - const double colRight = currentLeft + itemWidth; - const double scrollMax = std::max(ws->maxWidth() - USABLE.w, 0.0); - double desiredOffset; - - if (col == ws->columns.front()) - desiredOffset = 0.0; - else - desiredOffset = std::clamp(colRight - USABLE.w, 0.0, scrollMax); - - ws->leftOffset = desiredOffset; - break; - } - - currentLeft += itemWidth; - } - } else { - const auto columnToCenter = focusedColumn ? focusedColumn : fallbackColumn; - if (!columnToCenter) - continue; - - ws->centerCol(columnToCenter); - } - - ws->recalculate(); - } - } - return {}; -} - -SWindowRenderLayoutHints CScrollingLayout::requestRenderHints(PHLWINDOW a) { - return {}; -} - -void CScrollingLayout::switchWindows(PHLWINDOW a, PHLWINDOW b) { - const auto DATA1 = dataFor(a); - const auto DATA2 = dataFor(b); - - std::swap(DATA1->window, DATA2->window); - - const auto WS1 = DATA1->column->workspace.lock(); - const auto WS2 = DATA2->column->workspace.lock(); - - WS1->recalculate(); - - if (WS1 == WS2) - return; - - WS2->recalculate(); -} - -void CScrollingLayout::moveWindowTo(PHLWINDOW w, const std::string& dir, bool silent) { - const auto DATA = dataFor(w); - - if (!DATA) - return; - - const auto WS = DATA->column->workspace.lock(); - - if (dir == "l") { - const auto COL = WS->prev(DATA->column.lock()); - - DATA->column->remove(w); - - if (!COL) { - const auto NEWCOL = WS->add(-1); - NEWCOL->add(DATA); - WS->centerOrFitCol(NEWCOL); - } else { - if (COL->windowDatas.size() > 0) - COL->add(DATA, COL->idxForHeight(g_pInputManager->getMouseCoordsInternal().y)); - else - COL->add(DATA); - WS->centerOrFitCol(COL); - } - } else if (dir == "r") { - const auto COL = WS->next(DATA->column.lock()); - - DATA->column->remove(w); - - if (!COL) { - // make a new one - const auto NEWCOL = WS->add(); - NEWCOL->add(DATA); - WS->centerOrFitCol(NEWCOL); - } else { - if (COL->windowDatas.size() > 0) - COL->add(DATA, COL->idxForHeight(g_pInputManager->getMouseCoordsInternal().y)); - else - COL->add(DATA); - WS->centerOrFitCol(COL); - } - - } else if (dir == "t" || dir == "u") - DATA->column->up(DATA); - else if (dir == "b" || dir == "d") - DATA->column->down(DATA); - - WS->recalculate(); - focusWindowUpdate(w); - g_pCompositor->warpCursorTo(w->middle()); -} - -void CScrollingLayout::alterSplitRatio(PHLWINDOW, float, bool) { - ; -} - -std::string CScrollingLayout::getLayoutName() { - return "scrolling"; -} - -void CScrollingLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) { - ; -} - -Vector2D CScrollingLayout::predictSizeForNewWindowTiled() { - return Vector2D{}; -} - -SP CScrollingLayout::dataFor(PHLWORKSPACE ws) { - for (const auto& e : m_workspaceDatas) { - if (e->workspace != ws) - continue; - - return e; - } - - return nullptr; -} - -SP CScrollingLayout::dataFor(PHLWINDOW w) { - if (!w) - return nullptr; - - for (const auto& e : m_workspaceDatas) { - if (e->workspace != w->m_workspace) - continue; - - for (const auto& c : e->columns) { - for (const auto& d : c->windowDatas) { - if (d->window != w) - continue; - - return d; - } - } - } - - return nullptr; -} - -SP CScrollingLayout::currentWorkspaceData() { - if (!Desktop::focusState()->monitor() || !Desktop::focusState()->monitor()->m_activeWorkspace) - return nullptr; - - // FIXME: special - - return dataFor(Desktop::focusState()->monitor()->m_activeWorkspace); -} - -CBox CScrollingLayout::usableAreaFor(PHLMONITOR m) { - return workAreaOnWorkspace(m->m_activeWorkspace).translate(-m->m_position); -} diff --git a/hyprscrolling/Scrolling.hpp b/hyprscrolling/Scrolling.hpp deleted file mode 100644 index 3538548..0000000 --- a/hyprscrolling/Scrolling.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -class CScrollingLayout; -struct SColumnData; -struct SWorkspaceData; - -struct SScrollingWindowData { - SScrollingWindowData(PHLWINDOW w, SP col, float ws = 1.F) : window(w), column(col), windowSize(ws) { - ; - } - - PHLWINDOWREF window; - WP column; - float windowSize = 1.F; - bool ignoreFullscreenChecks = false; - PHLWORKSPACEREF overrideWorkspace; - - CBox layoutBox; -}; - -struct SColumnData { - SColumnData(SP ws) : workspace(ws) { - ; - } - - void add(PHLWINDOW w); - void add(PHLWINDOW w, int after); - void add(SP w); - void add(SP w, int after); - void remove(PHLWINDOW w); - bool has(PHLWINDOW w); - size_t idx(PHLWINDOW w); - - // index of lowest window that is above y. - size_t idxForHeight(float y); - - void up(SP w); - void down(SP w); - - SP next(SP w); - SP prev(SP w); - - std::vector> windowDatas; - float columnSize = 1.F; - float columnWidth = 1.F; - WP workspace; - WP lastFocusedWindow; - - WP self; -}; - -struct SWorkspaceData { - SWorkspaceData(PHLWORKSPACE w, CScrollingLayout* l) : workspace(w), layout(l) { - ; - } - - PHLWORKSPACEREF workspace; - std::vector> columns; - float leftOffset = 0; - - SP add(); - SP add(int after); - int64_t idx(SP c); - void remove(SP c); - double maxWidth(); - SP next(SP c); - SP prev(SP c); - SP atCenter(); - - bool visible(SP c); - void centerCol(SP c); - void fitCol(SP c); - void centerOrFitCol(SP c); - - void recalculate(bool forceInstant = false); - - CScrollingLayout* layout = nullptr; - WP self; -}; - -class CScrollingLayout : public IHyprLayout { - public: - virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); - virtual void onWindowRemovedTiling(PHLWINDOW); - virtual bool isWindowTiled(PHLWINDOW); - virtual void recalculateMonitor(const MONITORID&); - virtual void recalculateWindow(PHLWINDOW); - virtual void onBeginDragWindow(); - virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr); - virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE); - virtual std::any layoutMessage(SLayoutMessageHeader, std::string); - virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW); - virtual void switchWindows(PHLWINDOW, PHLWINDOW); - virtual void moveWindowTo(PHLWINDOW, const std::string& dir, bool silent); - virtual void alterSplitRatio(PHLWINDOW, float, bool); - virtual std::string getLayoutName(); - virtual void replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to); - virtual Vector2D predictSizeForNewWindowTiled(); - - virtual void onEnable(); - virtual void onDisable(); - - CBox usableAreaFor(PHLMONITOR m); - - private: - std::vector> m_workspaceDatas; - - SP m_configCallback; - SP m_focusCallback; - - struct { - bool isMovingColumn = false; - int targetWorkspaceID = -1; - } m_columnMoveState; - - struct { - std::vector configuredWidths; - } m_config; - - SP findBestNeighbor(SP pCurrent, SP pTargetCol); - SP dataFor(PHLWORKSPACE ws); - SP dataFor(PHLWINDOW w); - SP currentWorkspaceData(); - - void applyNodeDataToWindow(SP node, bool instant, bool hasWindowsRight, bool hasWindowsLeft); - void focusWindowUpdate(PHLWINDOW pWindow); - - friend struct SWorkspaceData; -}; diff --git a/hyprscrolling/default.nix b/hyprscrolling/default.nix deleted file mode 100644 index 1ae5e12..0000000 --- a/hyprscrolling/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - lib, - hyprland, - hyprlandPlugins, -}: -hyprlandPlugins.mkHyprlandPlugin { - pluginName = "hyprscrolling"; - version = "0.1"; - src = ./.; - - inherit (hyprland) nativeBuildInputs; - - meta = with lib; { - homepage = "https://github.com/hyprwm/hyprland-plugins/tree/main/hyprscrolling"; - description = "Hyprland scrolling layout plugin"; - license = licenses.bsd3; - platforms = platforms.linux; - }; -} diff --git a/hyprscrolling/globals.hpp b/hyprscrolling/globals.hpp deleted file mode 100644 index 2257475..0000000 --- a/hyprscrolling/globals.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -inline HANDLE PHANDLE = nullptr; \ No newline at end of file diff --git a/hyprscrolling/main.cpp b/hyprscrolling/main.cpp deleted file mode 100644 index 4f09173..0000000 --- a/hyprscrolling/main.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#define WLR_USE_UNSTABLE - -#include - -#include -#include - -#define private public -#include -#include -#include -#include -#include -#undef private - -#include -using namespace Hyprutils::String; - -#include "globals.hpp" -#include "Scrolling.hpp" - -// Do NOT change this function. -APICALL EXPORT std::string PLUGIN_API_VERSION() { - return HYPRLAND_API_VERSION; -} - -UP g_pScrollingLayout; - -// - -APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { - PHANDLE = handle; - - const std::string HASH = __hyprland_api_get_hash(); - const std::string CLIENT_HASH = __hyprland_api_get_client_hash(); - - if (HASH != CLIENT_HASH) { - HyprlandAPI::addNotification(PHANDLE, "[hyprscrolling] Failure in initialization: Version mismatch (headers ver is not equal to running hyprland ver)", - CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); - throw std::runtime_error("[hs] Version mismatch"); - } - - bool success = true; - - g_pScrollingLayout = makeUnique(); - - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprscrolling:fullscreen_on_one_column", Hyprlang::INT{0}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprscrolling:column_width", Hyprlang::FLOAT{0.5F}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprscrolling:focus_fit_method", Hyprlang::INT{0}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprscrolling:follow_focus", Hyprlang::INT{1}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprscrolling:follow_debounce_ms", Hyprlang::INT{0}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprscrolling:explicit_column_widths", Hyprlang::STRING{"0.333, 0.5, 0.667, 1.0"}); - HyprlandAPI::addLayout(PHANDLE, "scrolling", g_pScrollingLayout.get()); - - if (!success) { - HyprlandAPI::addNotification(PHANDLE, "[hyprscrolling] Failure in initialization: failed to register dispatchers", CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); - throw std::runtime_error("[hs] Dispatchers failed"); - } - - return {"hyprscrolling", "A plugin to add a scrolling layout to hyprland", "Vaxry", "1.0"}; -} - -APICALL EXPORT void PLUGIN_EXIT() { - HyprlandAPI::removeLayout(PHANDLE, g_pScrollingLayout.get()); - g_pScrollingLayout.reset(); -} diff --git a/hyprscrolling/meson.build b/hyprscrolling/meson.build deleted file mode 100644 index e3debe0..0000000 --- a/hyprscrolling/meson.build +++ /dev/null @@ -1,30 +0,0 @@ -project('hyprscrolling', 'cpp', - version: '0.1', - default_options: ['buildtype=release'], -) - -cpp_compiler = meson.get_compiler('cpp') -if cpp_compiler.has_argument('-std=c++23') - add_global_arguments('-std=c++23', language: 'cpp') -elif cpp_compiler.has_argument('-std=c++2b') - add_global_arguments('-std=c++2b', language: 'cpp') -else - error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') -endif - -globber = run_command('find', '.', '-name', '*.cpp', check: true) -src = globber.stdout().strip().split('\n') - -shared_module(meson.project_name(), src, - dependencies: [ - dependency('hyprland'), - dependency('pixman-1'), - dependency('libdrm'), - dependency('pangocairo'), - dependency('libinput'), - dependency('libudev'), - dependency('wayland-server'), - dependency('xkbcommon'), - ], - install: true, -) diff --git a/hyprtrails/CMakeLists.txt b/hyprtrails/CMakeLists.txt deleted file mode 100644 index 74ca9f6..0000000 --- a/hyprtrails/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.27) - -project(hyprtrails - DESCRIPTION "hyprtrails plugin for Hyprland" - VERSION 0.1 -) - -set(CMAKE_CXX_STANDARD 23) - -file(GLOB_RECURSE SRC "*.cpp") - -add_library(hyprtrails SHARED ${SRC}) - -find_package(PkgConfig REQUIRED) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET - hyprland - libdrm - libinput - libudev - pangocairo - pixman-1 - wayland-server - xkbcommon -) -target_link_libraries(hyprtrails PRIVATE rt PkgConfig::deps) - -install(TARGETS hyprtrails) diff --git a/hyprtrails/Makefile b/hyprtrails/Makefile deleted file mode 100644 index 983c604..0000000 --- a/hyprtrails/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Else exist specifically for clang -ifeq ($(CXX),g++) - EXTRA_FLAGS = --no-gnu-unique -else - EXTRA_FLAGS = -endif - -CXXFLAGS ?= -O2 -CXXFLAGS += -shared -fPIC -std=c++2b - -all: - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_FLAGS) main.cpp trail.cpp TrailPassElement.cpp -o hyprtrails.so `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` -clean: - rm ./hyprtrails.so diff --git a/hyprtrails/README.md b/hyprtrails/README.md deleted file mode 100644 index 3f168c1..0000000 --- a/hyprtrails/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# hyprtrails - -A neat, but useless plugin to add trails behind windows: - -https://github.com/hyprwm/hyprland-plugins/assets/43317083/6c31b839-92cd-4510-bb12-110d77dd5b44 - -Maybe isn't the most efficient. The curve-related settings are only for advanced users. -Be warned they _incredibly_ impact performance. - -Only setting you may want to change: -```ini -plugin { - hyprtrails { - color = rgba(ffaa00ff) - } -} - -``` diff --git a/hyprtrails/TrailPassElement.cpp b/hyprtrails/TrailPassElement.cpp deleted file mode 100644 index c5bf781..0000000 --- a/hyprtrails/TrailPassElement.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "TrailPassElement.hpp" -#include -#include -#include "trail.hpp" - -CTrailPassElement::CTrailPassElement(const CTrailPassElement::STrailData& data_) : data(data_) { - ; -} - -std::vector> CTrailPassElement::draw() { - data.deco->renderPass(g_pHyprRenderer->m_renderData.pMonitor.lock(), data.a); - return {}; -} - -bool CTrailPassElement::needsLiveBlur() { - return false; -} - -bool CTrailPassElement::needsPrecomputeBlur() { - return false; -} diff --git a/hyprtrails/TrailPassElement.hpp b/hyprtrails/TrailPassElement.hpp deleted file mode 100644 index ff33ff1..0000000 --- a/hyprtrails/TrailPassElement.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -#include - -class CTrail; - -class CTrailPassElement : public IPassElement { - public: - struct STrailData { - CTrail* deco = nullptr; - float a = 1.F; - }; - - CTrailPassElement(const STrailData& data_); - virtual ~CTrailPassElement() = default; - - virtual std::vector> draw() override; - virtual bool needsLiveBlur() override; - virtual bool needsPrecomputeBlur() override; - - virtual const char* passName() override { - return "CTrailPassElement"; - } - - virtual ePassElementType type() override { - return EK_CUSTOM; - } - - private: - STrailData data; -}; diff --git a/hyprtrails/default.nix b/hyprtrails/default.nix deleted file mode 100644 index 1548c05..0000000 --- a/hyprtrails/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - lib, - hyprland, - hyprlandPlugins, -}: -hyprlandPlugins.mkHyprlandPlugin { - pluginName = "hyprtrails"; - version = "0.1"; - src = ./.; - - inherit (hyprland) nativeBuildInputs; - - meta = with lib; { - homepage = "https://github.com/hyprwm/hyprland-plugins/tree/main/hyprtrails"; - description = "Smooth trails behind moving windows for Hyprland"; - license = licenses.bsd3; - platforms = platforms.linux; - }; -} diff --git a/hyprtrails/globals.hpp b/hyprtrails/globals.hpp deleted file mode 100644 index 87bc18f..0000000 --- a/hyprtrails/globals.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include -#include - -class CEventLoopTimer; -class CTrail; - -inline HANDLE PHANDLE = nullptr; - -struct SGlobalState { - CShader trailShader; - SP tick; - std::vector trails; -}; - -inline UP g_pGlobalState; diff --git a/hyprtrails/main.cpp b/hyprtrails/main.cpp deleted file mode 100644 index cec5f09..0000000 --- a/hyprtrails/main.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#define WLR_USE_UNSTABLE - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "globals.hpp" -#include "shaders.hpp" -#include "trail.hpp" - -// Do NOT change this function. -APICALL EXPORT std::string PLUGIN_API_VERSION() { - return HYPRLAND_API_VERSION; -} - -void onNewWindow(PHLWINDOW PWINDOW) { - HyprlandAPI::addWindowDecoration(PHANDLE, PWINDOW, makeUnique(PWINDOW)); -} - -static void onTick(SP self, void* data) { - tickTrails(); - - const int timeoutMs = g_pHyprRenderer->m_mostHzMonitor ? 1000.0 / g_pHyprRenderer->m_mostHzMonitor->m_refreshRate : 16; - self->updateTimeout(std::chrono::milliseconds(timeoutMs)); -} - -void initGlobal() { - Render::GL::g_pHyprOpenGL->makeEGLCurrent(); - - if (!g_pGlobalState->trailShader.createProgram(QUADTRAIL, FRAGTRAIL, true, false)) - throw std::runtime_error("[ht] Failed to create trail shader"); - - 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) { - PHANDLE = handle; - - const std::string HASH = __hyprland_api_get_hash(); - const std::string CLIENT_HASH = __hyprland_api_get_client_hash(); - - if (HASH != CLIENT_HASH) { - HyprlandAPI::addNotification(PHANDLE, "[ht] Failure in initialization: Version mismatch (headers ver is not equal to running hyprland ver)", CHyprColor{1.0, 0.2, 0.2, 1.0}, - 5000); - throw std::runtime_error("[ht] Version mismatch"); - } - - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprtrails:bezier_step", Hyprlang::FLOAT{0.025}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprtrails:points_per_step", Hyprlang::INT{2}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprtrails:history_points", Hyprlang::INT{20}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprtrails:history_step", Hyprlang::INT{2}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprtrails:color", Hyprlang::INT{*configStringToInt("rgba(ffaa00ff)")}); - - static auto P = Event::bus()->m_events.window.open.listen([&](PHLWINDOW w) { onNewWindow(w); }); - - g_pGlobalState = makeUnique(); - initGlobal(); - - // add deco to existing windows - for (auto& w : g_pCompositor->m_windows) { - if (w->isHidden() || !w->m_isMapped) - continue; - - HyprlandAPI::addWindowDecoration(PHANDLE, w, makeUnique(w)); - } - - HyprlandAPI::reloadConfig(); - - HyprlandAPI::addNotification(PHANDLE, "[hyprtrails] Initialized successfully!", CHyprColor{0.2, 1.0, 0.2, 1.0}, 5000); - - return {"hyprtrails", "A plugin to add trails behind moving windows", "Vaxry", "1.0"}; -} - -APICALL EXPORT void PLUGIN_EXIT() { - 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/meson.build b/hyprtrails/meson.build deleted file mode 100644 index 47dbcb3..0000000 --- a/hyprtrails/meson.build +++ /dev/null @@ -1,38 +0,0 @@ -project('hyprtrails', 'cpp', - version: '0.1', - default_options: ['buildtype=release'], -) - -cpp_compiler = meson.get_compiler('cpp') -if cpp_compiler.has_argument('-std=c++23') - add_global_arguments('-std=c++23', language: 'cpp') -elif cpp_compiler.has_argument('-std=c++2b') - add_global_arguments('-std=c++2b', language: 'cpp') -else - error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') -endif - -add_project_arguments( - [ - '-Wno-narrowing', - ], - language: 'cpp') - -globber = run_command('find', '.', '-name', '*.cpp', check: true) -src = globber.stdout().strip().split('\n') - -hyprland = dependency('hyprland') - -shared_module(meson.project_name(), src, - dependencies: [ - dependency('hyprland'), - dependency('pixman-1'), - dependency('libdrm'), - dependency('pangocairo'), - dependency('libinput'), - dependency('libudev'), - dependency('wayland-server'), - dependency('xkbcommon'), - ], - install: true, -) diff --git a/hyprtrails/shaders.hpp b/hyprtrails/shaders.hpp deleted file mode 100644 index 83e0c63..0000000 --- a/hyprtrails/shaders.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -inline const std::string QUADTRAIL = R"#( -#version 300 es -precision mediump float; -uniform mat3 proj; -uniform vec4 color; -in vec2 pos; -in vec2 texcoord; -in vec4 colors; -out vec4 v_color; -out vec2 v_texcoord; - -void main() { - gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); - v_color = color; - v_texcoord = texcoord; -})#"; - -inline const std::string FRAGTRAIL = R"#( -#version 300 es -precision mediump float; -in vec4 v_color; -in vec2 v_texcoord; - -uniform vec4 window; - -layout(location = 0) out vec4 fragColor; - -float distToRect(vec4 rect) { - float dx = max(rect[0] - v_texcoord[0], max(0.0, v_texcoord[0] - rect[2])); - float dy = max(rect[1] - v_texcoord[1], max(0.0, v_texcoord[1] - rect[3])); - return sqrt(dx*dx + dy*dy); -} - -float alphaForShot(vec4 shot, float threshold) { - - float dist = distToRect(shot); - - if (dist > threshold) - return 0.0; - - if (dist <= 0.0) - return 0.0; - - return 1.0 - (dist * (1.0 / threshold)); -} - -void main() { - - vec4 pixColor = v_color; - float a = v_color[3]; // clamp(alphaForShot(window, 0.5), 0.0, 1.0); // todo - - pixColor.rgb *= a; - - fragColor = pixColor; -})#"; diff --git a/hyprtrails/trail.cpp b/hyprtrails/trail.cpp deleted file mode 100644 index ebf1553..0000000 --- a/hyprtrails/trail.cpp +++ /dev/null @@ -1,355 +0,0 @@ -#include "trail.hpp" - -#include -#include -#include -#include -#include -using namespace Hyprutils::Memory; -using namespace Render::GL; -#include "globals.hpp" -#include "TrailPassElement.hpp" - -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(); - - if (m_iTimer > **PHISTORYSTEP) { - m_dLastGeoms.push_front({box{(float)PWINDOW->m_realPosition->value().x, (float)PWINDOW->m_realPosition->value().y, (float)PWINDOW->m_realSize->value().x, - (float)PWINDOW->m_realSize->value().y}, - std::chrono::system_clock::now()}); - while (m_dLastGeoms.size() > **PHISTORYPOINTS) - m_dLastGeoms.pop_back(); - - m_iTimer = 0; - } - - if (m_bNeedsDamage) { - g_pHyprRenderer->damageBox(m_bLastBox); - m_bNeedsDamage = false; - } -} - -CTrail::CTrail(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow), m_pWindow(pWindow) { - m_lastWindowPos = pWindow->m_realPosition->value(); - m_lastWindowSize = pWindow->m_realSize->value(); - - if (g_pGlobalState) - g_pGlobalState->trails.push_back(this); -} - -CTrail::~CTrail() { - damageEntire(); - - if (g_pGlobalState) - std::erase(g_pGlobalState->trails, this); -} - -SDecorationPositioningInfo CTrail::getPositioningInfo() { - return {DECORATION_POSITION_ABSOLUTE}; -} - -void CTrail::onPositioningReply(const SDecorationPositioningReply& reply) { - ; // ignored -} - -void scaleBox2(box& box, float coeff) { - float hwl = (box.w - (box.w * coeff)) / 2.0; - float hhl = (box.h - (box.h * coeff)) / 2.0; - - box.w *= coeff; - box.h *= coeff; - box.x += hwl; - box.y += hhl; -} - -Vector2D vecForT(const Vector2D& a, const Vector2D& b, const float& t) { - const Vector2D vec_PQ = b - a; - return Vector2D{a + vec_PQ * t}; -} - -Vector2D vecForBezierT(const float& t, const std::vector& verts) { - std::vector pts; - - for (size_t vertexIndex = 0; vertexIndex < verts.size() - 1; vertexIndex++) { - Vector2D p = verts[vertexIndex]; - pts.push_back(vecForT(p, verts[vertexIndex + 1], t)); - } - - if (pts.size() > 1) - return vecForBezierT(t, pts); - else - return pts[0]; -} - -void CTrail::draw(PHLMONITOR pMonitor, const float& a) { - if (!validMapped(m_pWindow)) - return; - - const auto PWINDOW = m_pWindow.lock(); - - if (!PWINDOW->m_ruleApplicator->decorate().valueOrDefault()) - return; - - auto data = CTrailPassElement::STrailData{this, a}; - g_pHyprRenderer->m_renderPass.add(makeUnique(data)); -} - -void CTrail::renderPass(PHLMONITOR pMonitor, const float& a) { - const auto PWINDOW = m_pWindow.lock(); - - static auto* const PBEZIERSTEP = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprtrails:bezier_step")->getDataStaticPtr(); - static auto* const PPOINTSPERSTEP = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprtrails:points_per_step")->getDataStaticPtr(); - static auto* const PCOLOR = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprtrails:color")->getDataStaticPtr(); - - const CHyprColor COLOR = **PCOLOR; - - if (m_dLastGeoms.size() < 2) - return; - - box thisbox = - box{(float)PWINDOW->m_realPosition->value().x, (float)PWINDOW->m_realPosition->value().y, (float)PWINDOW->m_realSize->value().x, (float)PWINDOW->m_realSize->value().y}; - CBox wlrbox = {thisbox.x - pMonitor->m_position.x, thisbox.y - pMonitor->m_position.y, thisbox.w, thisbox.h}; - wlrbox.scale(pMonitor->m_scale).round(); - - g_pHyprOpenGL->scissor(nullptr); // allow the entire window and stencil to render - glClearStencil(0); - glClear(GL_STENCIL_BUFFER_BIT); - - g_pHyprOpenGL->setCapStatus(GL_STENCIL_TEST, true); - - glStencilFunc(GL_ALWAYS, 1, -1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - g_pHyprOpenGL->renderRect(wlrbox, CHyprColor(0, 0, 0, 0), {.round = sc(PWINDOW->rounding() * pMonitor->m_scale), .roundingPower = PWINDOW->roundingPower()}); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - glStencilFunc(GL_NOTEQUAL, 1, -1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - CBox monbox = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y}; - - Mat3x3 glMatrix = g_pHyprRenderer->projectBoxToTarget(monbox, Math::wlTransformToHyprutils(Math::invertTransform(WL_OUTPUT_TRANSFORM_NORMAL))); - - g_pHyprOpenGL->blend(true); - - glUseProgram(g_pGlobalState->trailShader.program()); - - glMatrix.transpose(); - g_pGlobalState->trailShader.setUniformMatrix3fv(SHADER_PROJ, 1, GL_FALSE, glMatrix.getMatrix()); - - std::vector points; - std::vector bezierPts; - std::vector pointsForBezier; - std::vector agesForBezier; - - float originalCoeff = 50; - - auto msFrom = [](std::chrono::system_clock::time_point t) -> float { - return std::chrono::duration_cast(std::chrono::system_clock::now() - t).count() / 1000.0; - }; - - auto dist = [&](const point2& a, const point2& b) -> float { - Vector2D diff = Vector2D{a.x - b.x, a.y - b.y} * pMonitor->m_size; - return std::sqrt(diff.x * diff.x + diff.y * diff.y); - }; - - float msMaxToLast = msFrom(m_dLastGeoms.back().second); - - float dists[2] = {0, 0}; - - Vector2D mainVec = {originalCoeff / pMonitor->m_size.x, originalCoeff / pMonitor->m_size.y}; - Vector2D windowMiddle = PWINDOW->middle() - pMonitor->m_position; - - points.push_back( - Vector2D{cos(0) * mainVec.x - sin(0) * mainVec.y + windowMiddle.x / pMonitor->m_size.x, sin(0) * mainVec.x + cos(0) * mainVec.y + windowMiddle.y / pMonitor->m_size.y}); - points.push_back(Vector2D{cos(-M_PI_2) * mainVec.x - sin(-M_PI_2) * mainVec.y + windowMiddle.x / pMonitor->m_size.x, - sin(-M_PI_2) * mainVec.x + cos(-M_PI_2) * mainVec.y + windowMiddle.y / pMonitor->m_size.y}); - points.push_back(Vector2D{cos(M_PI_2) * mainVec.x - sin(M_PI_2) * mainVec.y + windowMiddle.x / pMonitor->m_size.x, - sin(M_PI_2) * mainVec.x + cos(M_PI_2) * mainVec.y + windowMiddle.y / pMonitor->m_size.y}); - points.push_back(Vector2D{cos(M_PI) * mainVec.x - sin(M_PI) * mainVec.y + windowMiddle.x / pMonitor->m_size.x, - sin(M_PI) * mainVec.x + cos(M_PI) * mainVec.y + windowMiddle.y / pMonitor->m_size.y}); - - pointsForBezier.push_back(windowMiddle); - agesForBezier.push_back(0); - - for (size_t i = 0; i < m_dLastGeoms.size(); i += 1) { - box box = m_dLastGeoms[i].first; - box.x -= pMonitor->m_position.x; - box.y -= pMonitor->m_position.y; - Vector2D middle = {box.x + box.w / 2.0, box.y + box.h / 2.0}; - - if (middle == pointsForBezier[pointsForBezier.size() - 1]) - continue; - - pointsForBezier.push_back(middle); - agesForBezier.push_back(msFrom(m_dLastGeoms[i].second)); - } - - if (pointsForBezier.size() < 3) { - glClearStencil(0); - glClear(GL_STENCIL_BUFFER_BIT); - g_pHyprOpenGL->setCapStatus(GL_STENCIL_TEST, false); - - glStencilMask(-1); - glStencilFunc(GL_ALWAYS, 1, 0xFF); - g_pHyprOpenGL->scissor(nullptr); - return; - } - - float maxAge = agesForBezier.back(); - float tCoeff = **PBEZIERSTEP; - int pointsPerBezier = **PPOINTSPERSTEP; - bezierPts.push_back(vecForBezierT(0, pointsForBezier)); - for (float t = tCoeff; t <= 1.0; t += tCoeff) { - bezierPts.push_back(vecForBezierT(t, pointsForBezier)); - - const Vector2D& lastbezier = bezierPts.back(); - const Vector2D& lastprevbezier = bezierPts[bezierPts.size() - 2]; - - for (size_t i = 1; i < pointsPerBezier + 1; ++i) { - const float bezierPointStep = (1.0 / (pointsPerBezier + 2)); - const Vector2D& middle = vecForT(lastprevbezier, lastbezier, bezierPointStep * (i + 1)); - const Vector2D& lastmiddle = vecForT(lastprevbezier, lastbezier, bezierPointStep * i); - - Vector2D vecNormal = {middle.x - lastmiddle.x, middle.y - lastmiddle.y}; - - // normalize vec - float invlen = 1.0 / std::sqrt(vecNormal.x * vecNormal.x + vecNormal.y * vecNormal.y); - vecNormal.x *= invlen; - vecNormal.y *= invlen; - - // make sure it points up - // vecNormal.y = std::abs(vecNormal.y); - - // extend by coeff - float ageCoeff = t * (agesForBezier.size() - 1); - float ageFloor = std::floor(ageCoeff); - float ageCeil = std::ceil(ageCoeff); - float approxAge = agesForBezier[sc(ageFloor)] + (agesForBezier[sc(ageCeil)] - agesForBezier[sc(ageFloor)]) * (ageCoeff - ageFloor); - float coeff = originalCoeff * (1.0 - (approxAge / maxAge)); - Vector2D newVec = {vecNormal.x * coeff / pMonitor->m_size.x, vecNormal.y * coeff / pMonitor->m_size.y}; - - if ((newVec.x == 0 && newVec.y == 0) || std::isnan(newVec.x) || std::isnan(newVec.y)) - continue; - - // rotate by 90 and -90 and add middle - points.push_back(Vector2D{cos(M_PI_2) * newVec.x - sin(M_PI_2) * newVec.y + middle.x / pMonitor->m_size.x, - sin(M_PI_2) * newVec.x + cos(M_PI_2) * newVec.y + middle.y / pMonitor->m_size.y}); - points.push_back(Vector2D{cos(-M_PI_2) * newVec.x - sin(-M_PI_2) * newVec.y + middle.x / pMonitor->m_size.x, - sin(-M_PI_2) * newVec.x + cos(-M_PI_2) * newVec.y + middle.y / pMonitor->m_size.y}); - } - } - - box thisboxopengl = box{sc((PWINDOW->m_realPosition->value().x - pMonitor->m_position.x) / pMonitor->m_size.x), - 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.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_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.getUniformLocation(SHADER_POS_ATTRIB), 2, GL_FLOAT, GL_FALSE, 0, (float*)points.data()); - - glEnableVertexAttribArray(g_pGlobalState->trailShader.getUniformLocation(SHADER_POS_ATTRIB)); - - 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()) { - g_pHyprOpenGL->scissor(&RECT); - glDrawArrays(GL_TRIANGLE_STRIP, 0, points.size()); - } - } - } else { - for (auto& RECT : g_pHyprRenderer->m_renderData.damage.getRects()) { - g_pHyprOpenGL->scissor(&RECT); - glDrawArrays(GL_TRIANGLE_STRIP, 0, points.size()); - } - } - - glDisableVertexAttribArray(g_pGlobalState->trailShader.getUniformLocation(SHADER_POS_ATTRIB)); - - glClearStencil(0); - glClear(GL_STENCIL_BUFFER_BIT); - g_pHyprOpenGL->setCapStatus(GL_STENCIL_TEST, false); - - glStencilMask(-1); - glStencilFunc(GL_ALWAYS, 1, 0xFF); - g_pHyprOpenGL->scissor(nullptr); - - // calculate damage - float minX = 9999999; - float minY = 9999999; - float maxX = -9999999; - float maxY = -9999999; - - for (auto& p : points) { - if (p.x < minX) - minX = p.x; - if (p.y < minY) - minY = p.y; - if (p.x > maxX) - maxX = p.x; - if (p.y > maxY) - maxY = p.y; - } - - // bring back to global coords - minX *= pMonitor->m_size.x; - minY *= pMonitor->m_size.y; - maxX *= pMonitor->m_size.x; - maxY *= pMonitor->m_size.y; - - m_bLastBox.x = minX + pMonitor->m_position.x; - m_bLastBox.y = minY + pMonitor->m_position.y; - m_bLastBox.width = maxX - minX; - m_bLastBox.height = maxY - minY; - - m_bNeedsDamage = true; -} - -eDecorationType CTrail::getDecorationType() { - return DECORATION_CUSTOM; -} - -void CTrail::updateWindow(PHLWINDOW pWindow) { - const auto PWORKSPACE = pWindow->m_workspace; - - const auto WORKSPACEOFFSET = PWORKSPACE && !pWindow->m_pinned ? PWORKSPACE->m_renderOffset->value() : Vector2D(); - - m_lastWindowPos = pWindow->m_realPosition->value() + WORKSPACEOFFSET; - m_lastWindowSize = pWindow->m_realSize->value(); - - damageEntire(); -} - -void CTrail::damageEntire() { - CBox dm = {sc(m_lastWindowPos.x - m_seExtents.topLeft.x), sc(m_lastWindowPos.y - m_seExtents.topLeft.y), - 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 deleted file mode 100644 index e2e259d..0000000 --- a/hyprtrails/trail.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#define WLR_USE_UNSTABLE - -#include -#include -#include - -struct box { - float x = 0, y = 0, w = 0, h = 0; - - // - Vector2D middle() { - return Vector2D{x + w / 2.0, y + h / 2.0}; - } -}; -struct point2 { - point2(const Vector2D& v) { - x = v.x; - y = v.y; - } - - point2() { - x = 0; - y = 0; - } - - float x = 0, y = 0; -}; - -class CTrail : public IHyprWindowDecoration { - public: - CTrail(PHLWINDOW); - virtual ~CTrail(); - - virtual SDecorationPositioningInfo getPositioningInfo(); - - virtual void onPositioningReply(const SDecorationPositioningReply& reply); - - virtual void draw(PHLMONITOR, float const& a); - - virtual eDecorationType getDecorationType(); - - virtual void updateWindow(PHLWINDOW); - - virtual void damageEntire(); - - private: - void onTick(); - void renderPass(PHLMONITOR pMonitor, const float& a); - - std::deque> m_dLastGeoms; - - int m_iTimer = 0; - - SBoxExtents m_seExtents; - - PHLWINDOWREF m_pWindow; - - Vector2D m_lastWindowPos; - Vector2D m_lastWindowSize; - - CBox m_bLastBox = {0}; - bool m_bNeedsDamage = false; - - friend class CTrailPassElement; - friend void tickTrails(); -}; - -void tickTrails(); diff --git a/hyprwinwrap/CMakeLists.txt b/hyprwinwrap/CMakeLists.txt deleted file mode 100644 index 1d5931a..0000000 --- a/hyprwinwrap/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.27) - -project(hyprwinwrap - DESCRIPTION "hyprwinwrap plugin for Hyprland" - VERSION 0.1 -) - -set(CMAKE_CXX_STANDARD 23) - -file(GLOB_RECURSE SRC "*.cpp") - -add_library(hyprwinwrap SHARED ${SRC}) - -find_package(PkgConfig REQUIRED) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET - hyprland - libdrm - libinput - libudev - pangocairo - pixman-1 - wayland-server - xkbcommon -) -target_link_libraries(hyprwinwrap PRIVATE rt PkgConfig::deps) - -install(TARGETS hyprwinwrap) diff --git a/hyprwinwrap/Makefile b/hyprwinwrap/Makefile deleted file mode 100644 index 45b6c7a..0000000 --- a/hyprwinwrap/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Else exist specifically for clang -ifeq ($(CXX),g++) - EXTRA_FLAGS = --no-gnu-unique -else - EXTRA_FLAGS = -endif - -CXXFLAGS ?= -O2 -CXXFLAGS += -shared -fPIC -std=c++2b - -all: - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_FLAGS) main.cpp -o hyprwinwrap.so `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` -clean: - rm ./hyprwinwrap.so diff --git a/hyprwinwrap/README.md b/hyprwinwrap/README.md deleted file mode 100644 index 1963d5d..0000000 --- a/hyprwinwrap/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# hyprwinwrap - -Clone of xwinwrap for hyprland. - -Example config: -```ini -plugin { - hyprwinwrap { - # class is an EXACT match and NOT a regex! - class = kitty-bg - # you can also use title - title = kitty-bg - # you can add the position of the window in a percentage - pos_x = 25 - pos_y = 30 - # you can add the size of the window in a percentage - size_x = 40 - size_y = 70 - } -} - -``` - -Launch `kitty -c "~/.config/hypr/kittyconfigbg.conf" --class="kitty-bg" "/home/vaxry/.config/hypr/cava.sh"` - -Example script for cava: - -```sh -#!/bin/sh -sleep 1 && cava -``` - -_sleep required because resizing happens a few ms after open, which breaks cava_ diff --git a/hyprwinwrap/default.nix b/hyprwinwrap/default.nix deleted file mode 100644 index 67ff8fb..0000000 --- a/hyprwinwrap/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - lib, - hyprland, - hyprlandPlugins, -}: -hyprlandPlugins.mkHyprlandPlugin { - pluginName = "hyprwinwrap"; - version = "0.1"; - src = ./.; - - inherit (hyprland) nativeBuildInputs; - - meta = with lib; { - homepage = "https://github.com/hyprwm/hyprland-plugins/tree/main/hyprwinwrap"; - description = "Hyprland version of xwinwrap"; - license = licenses.bsd3; - platforms = platforms.linux; - }; -} diff --git a/hyprwinwrap/globals.hpp b/hyprwinwrap/globals.hpp deleted file mode 100644 index 2257475..0000000 --- a/hyprwinwrap/globals.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -inline HANDLE PHANDLE = nullptr; \ No newline at end of file diff --git a/hyprwinwrap/main.cpp b/hyprwinwrap/main.cpp deleted file mode 100644 index c72d0ee..0000000 --- a/hyprwinwrap/main.cpp +++ /dev/null @@ -1,272 +0,0 @@ -#define WLR_USE_UNSTABLE - -#include -#include - -#include -#include -#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 -#include "globals.hpp" - -// Do NOT change this function -APICALL EXPORT std::string PLUGIN_API_VERSION() { - return HYPRLAND_API_VERSION; -} - -// hooks -inline CFunctionHook* subsurfaceHook = nullptr; -inline CFunctionHook* commitHook = nullptr; -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(); - static auto* const PTITLE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:title")->getDataStaticPtr(); - - static auto* const PSIZEX = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:size_x")->getDataStaticPtr(); - static auto* const PSIZEY = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:size_y")->getDataStaticPtr(); - static auto* const PPOSX = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:pos_x")->getDataStaticPtr(); - static auto* const PPOSY = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:pos_y")->getDataStaticPtr(); - - const std::string classRule(*PCLASS); - const std::string titleRule(*PTITLE); - - const bool classMatches = !classRule.empty() && pWindow->m_initialClass == classRule; - const bool titleMatches = !titleRule.empty() && pWindow->m_title == titleRule; - - if (!classMatches && !titleMatches) - return; - - const auto PMONITOR = pWindow->m_monitor.lock(); - if (!PMONITOR) - return; - - if (!pWindow->m_isFloating) - g_layoutManager->changeFloatingMode(pWindow->layoutTarget()); - - float sx = 100.f, sy = 100.f, px = 0.f, py = 0.f; - - try { - sx = std::stof(*PSIZEX); - } catch (...) {} - try { - sy = std::stof(*PSIZEY); - } catch (...) {} - try { - px = std::stof(*PPOSX); - } catch (...) {} - try { - py = std::stof(*PPOSY); - } catch (...) {} - - sx = std::clamp(sx, 1.f, 100.f); - sy = std::clamp(sy, 1.f, 100.f); - px = std::clamp(px, 0.f, 100.f); - py = std::clamp(py, 0.f, 100.f); - - if (px + sx > 100.f) { - Log::logger->log(Log::WARN, "[hyprwinwrap] size_x (%d) + pos_x (%d) > 100, adjusting size_x to %d", sx, px, 100.f - px); - sx = 100.f - px; - } - if (py + sy > 100.f) { - Log::logger->log(Log::WARN, "[hyprwinwrap] size_y (%d) + pos_y (%d) > 100, adjusting size_y to %d", sy, py, 100.f - py); - sy = 100.f - py; - } - - const Vector2D monitorSize = PMONITOR->m_size; - const Vector2D monitorPos = PMONITOR->m_position; - - const Vector2D newSize = {static_cast(monitorSize.x * (sx / 100.f)), static_cast(monitorSize.y * (sy / 100.f))}; - - const Vector2D newPos = {static_cast(monitorPos.x + (monitorSize.x * (px / 100.f))), static_cast(monitorPos.y + (monitorSize.y * (py / 100.f)))}; - - const CBox b(newPos.x, newPos.y, newSize.x, newSize.y); - - pWindow->layoutTarget()->space()->setTargetGeom(b, pWindow->layoutTarget()); - pWindow->m_realSize->setValueAndWarp(newSize); - pWindow->m_realPosition->setValueAndWarp(newPos); - pWindow->m_size = newSize; - pWindow->m_position = newPos; - pWindow->m_pinned = true; - pWindow->sendWindowSize(true); - - bgWindows.push_back(pWindow); - pWindow->m_hidden = true; - - g_pInputManager->refocus(); - Log::logger->log(Log::DEBUG, "[hyprwinwrap] new window moved to bg {}", pWindow); -} - -void onCloseWindow(PHLWINDOW pWindow) { - std::erase_if(bgWindows, [pWindow](const auto& ref) { return ref.expired() || ref.lock() == pWindow; }); - - Log::logger->log(Log::DEBUG, "[hyprwinwrap] closed window {}", pWindow); -} - -void onRenderStage(eRenderStage stage) { - if (stage != RENDER_POST_WALLPAPER) - return; - - for (auto& bg : bgWindows) { - const auto bgw = bg.lock(); - - 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_pHyprRenderer->m_renderData.pMonitor.lock(), Time::steadyNow(), false, RENDER_PASS_ALL, false, true); - - bgw->m_hidden = true; - } -} - -void onCommitSubsurface(Desktop::View::CSubsurface* thisptr) { - const auto PWINDOW = Desktop::View::CWindow::fromView(thisptr->wlSurface()->view()); - - if (!PWINDOW || std::find_if(bgWindows.begin(), bgWindows.end(), [PWINDOW](const auto& ref) { return ref.lock() == PWINDOW; }) == bgWindows.end()) { - ((origCommitSubsurface)subsurfaceHook->m_original)(thisptr); - return; - } - - // cant use setHidden cuz that sends suspended and shit too that would be laggy - PWINDOW->m_hidden = false; - - ((origCommitSubsurface)subsurfaceHook->m_original)(thisptr); - if (const auto MON = PWINDOW->m_monitor.lock(); MON) - g_pHyprRenderer->damageMonitor(MON); - - PWINDOW->m_hidden = true; -} - -void onCommit(void* owner, void* data) { - const auto PWINDOW = ((Desktop::View::CWindow*)owner)->m_self.lock(); - - if (std::find_if(bgWindows.begin(), bgWindows.end(), [PWINDOW](const auto& ref) { return ref.lock() == PWINDOW; }) == bgWindows.end()) { - ((origCommit)commitHook->m_original)(owner, data); - return; - } - - // cant use setHidden cuz that sends suspended and shit too that would be laggy - PWINDOW->m_hidden = false; - - ((origCommit)commitHook->m_original)(owner, data); - if (const auto MON = PWINDOW->m_monitor.lock(); 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()) { - 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()) { - 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) { - PHANDLE = handle; - - const std::string HASH = __hyprland_api_get_hash(); - const std::string CLIENT_HASH = __hyprland_api_get_client_hash(); - - if (HASH != CLIENT_HASH) { - HyprlandAPI::addNotification(PHANDLE, "[hyprwinwrap] Failure in initialization: Version mismatch (headers ver is not equal to running hyprland ver)", - CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); - throw std::runtime_error("[hww] Version mismatch"); - } - - static auto P = Event::bus()->m_events.window.open.listen([&](PHLWINDOW w) { onNewWindow(w); }); - static auto P2 = Event::bus()->m_events.window.close.listen([&](PHLWINDOW w) { onCloseWindow(w); }); - static auto P3 = Event::bus()->m_events.render.stage.listen([&](eRenderStage stage) { onRenderStage(stage); }); - static auto P4 = Event::bus()->m_events.config.reloaded.listen([&] { onConfigReloaded(); }); - - auto fns = HyprlandAPI::findFunctionsByName(PHANDLE, "_ZN7Desktop4View11CSubsurface8onCommitEv"); - if (fns.size() < 1) - throw std::runtime_error("hyprwinwrap: onCommit not found"); - subsurfaceHook = HyprlandAPI::createFunctionHook(PHANDLE, fns[0].address, (void*)&onCommitSubsurface); - - fns = HyprlandAPI::findFunctionsByName(PHANDLE, "_ZN7Desktop4View7CWindow12commitWindowEv"); - if (fns.size() < 1) - throw std::runtime_error("hyprwinwrap: listener_commitWindow not found"); - commitHook = HyprlandAPI::createFunctionHook(PHANDLE, fns[0].address, (void*)&onCommit); - - bool hkResult = subsurfaceHook->hook(); - hkResult = hkResult && commitHook->hook(); - - if (!hkResult) - throw std::runtime_error("hyprwinwrap: hooks failed"); - - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:class", Hyprlang::STRING{"kitty-bg"}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:title", Hyprlang::STRING{""}); - - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:size_x", Hyprlang::STRING{"100"}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:size_y", Hyprlang::STRING{"100"}); - 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/hyprwinwrap/meson.build b/hyprwinwrap/meson.build deleted file mode 100644 index 6e2010d..0000000 --- a/hyprwinwrap/meson.build +++ /dev/null @@ -1,30 +0,0 @@ -project('hyprwinwrap', 'cpp', - version: '0.1', - default_options: ['buildtype=release'], -) - -cpp_compiler = meson.get_compiler('cpp') -if cpp_compiler.has_argument('-std=c++23') - add_global_arguments('-std=c++23', language: 'cpp') -elif cpp_compiler.has_argument('-std=c++2b') - add_global_arguments('-std=c++2b', language: 'cpp') -else - error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') -endif - -globber = run_command('find', '.', '-name', '*.cpp', check: true) -src = globber.stdout().strip().split('\n') - -shared_module(meson.project_name(), src, - dependencies: [ - dependency('hyprland'), - dependency('pixman-1'), - dependency('libdrm'), - dependency('pangocairo'), - dependency('libinput'), - dependency('libudev'), - dependency('wayland-server'), - dependency('xkbcommon'), - ], - install: true, -) diff --git a/xtra-dispatchers/CMakeLists.txt b/xtra-dispatchers/CMakeLists.txt deleted file mode 100644 index 686f706..0000000 --- a/xtra-dispatchers/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.27) - -project(xtra-dispatchers - DESCRIPTION "xtra-dispatchers plugin for Hyprland" - VERSION 0.1 -) - -set(CMAKE_CXX_STANDARD 23) - -file(GLOB_RECURSE SRC "*.cpp") - -add_library(xtra-dispatchers SHARED ${SRC}) - -find_package(PkgConfig REQUIRED) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET - hyprland - libdrm - libinput - libudev - pangocairo - pixman-1 - wayland-server - xkbcommon -) -target_link_libraries(xtra-dispatchers PRIVATE rt PkgConfig::deps) - -install(TARGETS xtra-dispatchers) diff --git a/xtra-dispatchers/Makefile b/xtra-dispatchers/Makefile deleted file mode 100644 index d15bd9a..0000000 --- a/xtra-dispatchers/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Else exist specifically for clang -ifeq ($(CXX),g++) - EXTRA_FLAGS = --no-gnu-unique -else - EXTRA_FLAGS = -endif - -CXXFLAGS ?= -O2 -CXXFLAGS += -shared -fPIC -std=c++2b - -all: - $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_FLAGS) main.cpp -o xtra-dispatchers.so `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` -clean: - rm ./xtra-dispatchers.so diff --git a/xtra-dispatchers/README.md b/xtra-dispatchers/README.md deleted file mode 100644 index da5e62b..0000000 --- a/xtra-dispatchers/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# xtra-dispatchers - -Adds some additional dispatchers to Hyprland. - -## Dispatchers - -All dispatchers here are called `plugin:xtd:name` e.g. `plugin:xtd:moveorexec`. - -| name | description | params | -| -- | -- | -- | -| moveorexec | moves window to the current workspace, or executes if it's not found. `WINDOW` cannot contain commas | `WINDOW,CMD` | -| throwunfocused | throws all unfocused windows on the current workspace to the given workspace | `WORKSPACE` | -| bringallfrom | kinda inverse of throwunfocused. Bring all windows from a given workspace to the current one. | `WORKSPACE` | -| closeunfocused | close all unfocused windows on the current workspace. | none | diff --git a/xtra-dispatchers/default.nix b/xtra-dispatchers/default.nix deleted file mode 100644 index 50aca3f..0000000 --- a/xtra-dispatchers/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - lib, - hyprland, - hyprlandPlugins, -}: -hyprlandPlugins.mkHyprlandPlugin { - pluginName = "xtra-dispatchers"; - version = "0.1"; - src = ./.; - - inherit (hyprland) nativeBuildInputs; - - meta = with lib; { - homepage = "https://github.com/hyprwm/hyprland-plugins/tree/main/xtra-dispatchers"; - description = "Hyprland extra dispatchers plugin"; - license = licenses.bsd3; - platforms = platforms.linux; - }; -} diff --git a/xtra-dispatchers/globals.hpp b/xtra-dispatchers/globals.hpp deleted file mode 100644 index 2257475..0000000 --- a/xtra-dispatchers/globals.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -inline HANDLE PHANDLE = nullptr; \ No newline at end of file diff --git a/xtra-dispatchers/main.cpp b/xtra-dispatchers/main.cpp deleted file mode 100644 index 9a2fb73..0000000 --- a/xtra-dispatchers/main.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#define WLR_USE_UNSTABLE - -#include - -#include -#include - -#define private public -#include -#include -#include -#include -#include -#include -#include -#include -#undef private - -#include -using namespace Hyprutils::String; - -#include "globals.hpp" - -// Do NOT change this function. -APICALL EXPORT std::string PLUGIN_API_VERSION() { - return HYPRLAND_API_VERSION; -} - -// - -static SDispatchResult moveOrExec(std::string in) { - CVarList vars(in, 0, ','); - - auto focusState = Desktop::focusState(); - auto monitor = focusState->monitor(); - - if (!monitor || !monitor->m_activeWorkspace) - return SDispatchResult{.success = false, .error = "No active workspace"}; - - const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[0]); - - if (!PWINDOW) - Config::Supplementary::executor()->spawn(vars[1]); - else { - if (monitor->m_activeWorkspace != PWINDOW->m_workspace) - g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, monitor->m_activeWorkspace); - else - g_pCompositor->warpCursorTo(PWINDOW->middle()); - focusState->fullWindowFocus(PWINDOW, Desktop::FOCUS_REASON_KEYBIND); - } - - return SDispatchResult{}; -} - -static SDispatchResult throwUnfocused(std::string in) { - const auto [id, name, isAutoID] = getWorkspaceIDNameFromString(in); - - if (id == WORKSPACE_INVALID) - return SDispatchResult{.success = false, .error = "Failed to find workspace"}; - - auto focusState = Desktop::focusState(); - auto window = focusState->window(); - - if (!window || !window->m_workspace) - return SDispatchResult{.success = false, .error = "No valid last window"}; - - auto pWorkspace = g_pCompositor->getWorkspaceByID(id); - if (!pWorkspace) - pWorkspace = g_pCompositor->createNewWorkspace(id, window->m_workspace->monitorID(), name, false); - - for (const auto& w : g_pCompositor->m_windows) { - if (w == window || w->m_workspace != window->m_workspace) - continue; - - g_pCompositor->moveWindowToWorkspaceSafe(w, pWorkspace); - } - - return SDispatchResult{}; -} - -static SDispatchResult bringAllFrom(std::string in) { - const auto [id, name, isAutoID] = getWorkspaceIDNameFromString(in); - - if (id == WORKSPACE_INVALID) - return SDispatchResult{.success = false, .error = "Failed to find workspace"}; - - auto focusState = Desktop::focusState(); - auto monitor = focusState->monitor(); - auto window = focusState->window(); - - if (!monitor || !monitor->m_activeWorkspace) - return SDispatchResult{.success = false, .error = "No active monitor"}; - - auto pWorkspace = g_pCompositor->getWorkspaceByID(id); - if (!pWorkspace) - return SDispatchResult{.success = false, .error = "Workspace isnt open"}; - - const auto PLASTWINDOW = window; - - for (const auto& w : g_pCompositor->m_windows) { - if (w->m_workspace != pWorkspace) - continue; - - g_pCompositor->moveWindowToWorkspaceSafe(w, monitor->m_activeWorkspace); - } - - if (PLASTWINDOW) { - Desktop::focusState()->fullWindowFocus(PLASTWINDOW, Desktop::FOCUS_REASON_KEYBIND); - g_pCompositor->warpCursorTo(PLASTWINDOW->middle()); - } - - return SDispatchResult{}; -} - -static SDispatchResult closeUnfocused(std::string in) { - auto focusState = Desktop::focusState(); - auto monitor = focusState->monitor(); - auto window = focusState->window(); - - if (!window) - return SDispatchResult{.success = false, .error = "No focused monitor"}; - - for (const auto& w : g_pCompositor->m_windows) { - if (w->m_workspace != monitor->m_activeWorkspace || w->m_monitor != monitor || !w->m_isMapped || w == window) - continue; - - Config::Actions::closeWindow(w); - } - - return SDispatchResult{}; -} - -APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { - PHANDLE = handle; - - const std::string HASH = __hyprland_api_get_hash(); - const std::string CLIENT_HASH = __hyprland_api_get_client_hash(); - - if (HASH != CLIENT_HASH) { - HyprlandAPI::addNotification(PHANDLE, "[xtra-dispatchers] Failure in initialization: Version mismatch (headers ver is not equal to running hyprland ver)", - CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); - throw std::runtime_error("[xtd] Version mismatch"); - } - - bool success = true; - success = success && HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:xtd:moveorexec", ::moveOrExec); - success = success && HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:xtd:throwunfocused", ::throwUnfocused); - success = success && HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:xtd:bringallfrom", ::bringAllFrom); - success = success && HyprlandAPI::addDispatcherV2(PHANDLE, "plugin:xtd:closeunfocused", ::closeUnfocused); - - if (success) - HyprlandAPI::addNotification(PHANDLE, "[xtra-dispatchers] Initialized successfully!", CHyprColor{0.2, 1.0, 0.2, 1.0}, 5000); - else { - HyprlandAPI::addNotification(PHANDLE, "[xtra-dispatchers] Failure in initialization: failed to register dispatchers", CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); - throw std::runtime_error("[xtd] Dispatchers failed"); - } - - return {"xtra-dispatchers", "A plugin to add some extra dispatchers to hyprland", "Vaxry", "1.0"}; -} - -APICALL EXPORT void PLUGIN_EXIT() { - ; -} diff --git a/xtra-dispatchers/meson.build b/xtra-dispatchers/meson.build deleted file mode 100644 index e683d99..0000000 --- a/xtra-dispatchers/meson.build +++ /dev/null @@ -1,30 +0,0 @@ -project('xtra-dispatchers', 'cpp', - version: '0.1', - default_options: ['buildtype=release'], -) - -cpp_compiler = meson.get_compiler('cpp') -if cpp_compiler.has_argument('-std=c++23') - add_global_arguments('-std=c++23', language: 'cpp') -elif cpp_compiler.has_argument('-std=c++2b') - add_global_arguments('-std=c++2b', language: 'cpp') -else - error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') -endif - -globber = run_command('find', '.', '-name', '*.cpp', check: true) -src = globber.stdout().strip().split('\n') - -shared_module(meson.project_name(), src, - dependencies: [ - dependency('hyprland'), - dependency('pixman-1'), - dependency('libdrm'), - dependency('pangocairo'), - dependency('libinput'), - dependency('libudev'), - dependency('wayland-server'), - dependency('xkbcommon'), - ], - install: true, -)