├── LICENSE ├── Makefile ├── README.md ├── flake.lock ├── flake.nix ├── flash.gif ├── hyprload.toml ├── shrink.gif └── src ├── Flash.cpp ├── Flash.hpp ├── IFocusAnimation.cpp ├── IFocusAnimation.hpp ├── Shrink.cpp ├── Shrink.hpp └── main.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023, Vortex 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SOURCE_FILES=$(wildcard src/*.cpp src/*.hpp) 2 | 3 | all: 4 | $(CXX) -shared -fPIC --no-gnu-unique $(SOURCE_FILES) -o hyprfocus.so -g `pkg-config --cflags pixman-1 libdrm hyprland` -std=c++2b 5 | clean: 6 | rm ./hyprfocus.so 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### ⚠️ this repo is inactive and will be archived! please consider using [pyt0xic's fork](https://github.com/pyt0xic/hyprfocus) instead, as it's being actively maintained! 2 | 3 | # hyprfocus 4 | 5 | a plugin which provides focus animations for us borderless folks, originally inspired by [flashfocus](https://github.com/fennerm/flashfocus)! 6 | 7 | i'm on a tight schedule, so pull requests are welcome! 8 | 9 | ## animations 10 | 11 | flash 12 | 13 | ![preview](flash.gif) 14 | 15 | shrink 16 | 17 | ![preview](shrink.gif) 18 | 19 | ## compilation & installation 20 | 21 | instructions based on [the official wiki](https://wiki.hyprland.org/Plugins/Using-Plugins/#compiling-official-plugins) 22 | 23 | ### hyprpm 24 | 25 | **1) add hyprfocus** 26 | 27 | `hyprpm add https://github.com/VortexCoyote/hyprfocus` 28 | 29 | **2) verify that it's installed** 30 | 31 | `hyprpm list` 32 | 33 | **3) enable it and reload** 34 | 35 | `hyprpm enable hyprfocus && hyprpm reload` 36 | 37 | **4) (OPTIONAL) make sure plugins are loaded at startup** 38 | 39 | this goes into you hyprland config: 40 | ```exec-once = hyprpm reload -n``` 41 | 42 | ### manual 43 | 44 | **1) clone hyprfocus and cd into it** 45 | 46 | `git clone https://github.com/VortexCoyote/hyprfocus && cd hyprfocus` 47 | 48 | **2) clone hyprland and cd into it** 49 | 50 | `git clone --recursive https://github.com/hyprwm/Hyprland && cd Hyprland` 51 | 52 | **3) checkout the correct release tag matching with your version of hyprland** 53 | 54 | `git checkout tags/v0.26.0` 55 | 56 | **4) prepare the hyprland source for plugin compilation** 57 | 58 | `make all && sudo make installheaders` 59 | 60 | **5) cd back and make** 61 | 62 | `cd .. && make all` 63 | 64 | **6) profit,** make sure you use the full path to the .so file 65 | 66 | `hyprctl plugin load ` 67 | 68 | **If you compile hyprland manually and install with `sudo make install` you can skip the cloning hyprland sources and `make pluginenv` part.** 69 | 70 | ## getting started 71 | 72 | to start using hyprfocus, add this to your hyprland config: 73 | ``` 74 | plugin = 75 | 76 | plugin:hyprfocus { 77 | enabled = yes 78 | 79 | keyboard_focus_animation = shrink 80 | mouse_focus_animation = flash 81 | 82 | bezier = bezIn, 0.5,0.0,1.0,0.5 83 | bezier = bezOut, 0.0,0.5,0.5,1.0 84 | 85 | flash { 86 | flash_opacity = 0.7 87 | 88 | in_bezier = bezIn 89 | in_speed = 0.5 90 | 91 | out_bezier = bezOut 92 | out_speed = 3 93 | } 94 | 95 | shrink { 96 | shrink_percentage = 0.8 97 | 98 | in_bezier = bezIn 99 | in_speed = 0.5 100 | 101 | out_bezier = bezOut 102 | out_speed = 3 103 | } 104 | } 105 | ``` 106 | 107 | ### plugin configuration 108 | 109 | `enabled` (yes/no) -> enable or disable the plugin 110 | 111 | `keyboard_focus_animation` (flash/shrink/nothing) -> animation for keyboard-driven focus 112 | 113 | `mouse_focus_animation` (flash/shrink/nothing) -> animation for mouse pressed focus (setting input:follow_mouse = 0, input:float_switch_override_focus = 0 and input:mouse_refocus = false is recommended) 114 | 115 | ### animations configuration 116 | 117 | animations can be configured within the plugin scope with the following syntax: 118 | ``` 119 | plugin:hyprfocus { 120 | { 121 | 122 | } 123 | } 124 | ``` 125 | 126 | ### shared animation variables 127 | 128 | `in_bezier` (bezier) -> bezier curve towards the animation apex 129 | 130 | `out_bezier` (bezier) -> bezier curve towards the default window state 131 | 132 | `in_speed` (float) -> speed for the 'in' bezier 133 | 134 | `out_speed` (float) -> speed for the 'out' bezier 135 | 136 | ### flash 137 | 138 | `flash_opacity` (float) -> opacity to during the flash's apex 139 | 140 | ### shrink 141 | 142 | `shrink_percentage` (float) -> the amount a window has shrunk during the animation's apex 143 | 144 | ### dispatching 145 | 146 | hyprfocus can also flash the currently focused window through the `animatefocused` dispatcher: 147 | ``` 148 | bind = $mod, space, animatefocused 149 | ``` 150 | 151 | ## future plans 152 | 153 | I'm mostly planning on implementing more animations, for example a popin-popout bounce animation. But if you have any suggestions, feel free to create a git issue! 154 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "hyprland": { 4 | "inputs": { 5 | "hyprland-protocols": "hyprland-protocols", 6 | "nixpkgs": "nixpkgs", 7 | "systems": "systems", 8 | "wlroots": "wlroots", 9 | "xdph": "xdph" 10 | }, 11 | "locked": { 12 | "lastModified": 1698018813, 13 | "narHash": "sha256-JMg+HRyTOZK3W8pRNyJTp7AOWYkbs+LaKqAFc+cScyM=", 14 | "owner": "hyprwm", 15 | "repo": "Hyprland", 16 | "rev": "015664eb4cde5ab93cfacbfd8c2e831eeb876634", 17 | "type": "github" 18 | }, 19 | "original": { 20 | "owner": "hyprwm", 21 | "repo": "Hyprland", 22 | "type": "github" 23 | } 24 | }, 25 | "hyprland-protocols": { 26 | "inputs": { 27 | "nixpkgs": [ 28 | "hyprland", 29 | "nixpkgs" 30 | ], 31 | "systems": [ 32 | "hyprland", 33 | "systems" 34 | ] 35 | }, 36 | "locked": { 37 | "lastModified": 1691753796, 38 | "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", 39 | "owner": "hyprwm", 40 | "repo": "hyprland-protocols", 41 | "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", 42 | "type": "github" 43 | }, 44 | "original": { 45 | "owner": "hyprwm", 46 | "repo": "hyprland-protocols", 47 | "type": "github" 48 | } 49 | }, 50 | "nix-filter": { 51 | "locked": { 52 | "lastModified": 1694857738, 53 | "narHash": "sha256-bxxNyLHjhu0N8T3REINXQ2ZkJco0ABFPn6PIe2QUfqo=", 54 | "owner": "numtide", 55 | "repo": "nix-filter", 56 | "rev": "41fd48e00c22b4ced525af521ead8792402de0ea", 57 | "type": "github" 58 | }, 59 | "original": { 60 | "owner": "numtide", 61 | "repo": "nix-filter", 62 | "type": "github" 63 | } 64 | }, 65 | "nixpkgs": { 66 | "locked": { 67 | "lastModified": 1694767346, 68 | "narHash": "sha256-5uH27SiVFUwsTsqC5rs3kS7pBoNhtoy9QfTP9BmknGk=", 69 | "owner": "NixOS", 70 | "repo": "nixpkgs", 71 | "rev": "ace5093e36ab1e95cb9463863491bee90d5a4183", 72 | "type": "github" 73 | }, 74 | "original": { 75 | "owner": "NixOS", 76 | "ref": "nixos-unstable", 77 | "repo": "nixpkgs", 78 | "type": "github" 79 | } 80 | }, 81 | "root": { 82 | "inputs": { 83 | "hyprland": "hyprland", 84 | "nix-filter": "nix-filter" 85 | } 86 | }, 87 | "systems": { 88 | "locked": { 89 | "lastModified": 1689347949, 90 | "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", 91 | "owner": "nix-systems", 92 | "repo": "default-linux", 93 | "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", 94 | "type": "github" 95 | }, 96 | "original": { 97 | "owner": "nix-systems", 98 | "repo": "default-linux", 99 | "type": "github" 100 | } 101 | }, 102 | "wlroots": { 103 | "flake": false, 104 | "locked": { 105 | "host": "gitlab.freedesktop.org", 106 | "lastModified": 1696410538, 107 | "narHash": "sha256-ecDhdYLXWHsxMv+EWG36mCNDvzRbu9qfjH7dLxL7aGM=", 108 | "owner": "wlroots", 109 | "repo": "wlroots", 110 | "rev": "3406c1b17a4a7e6d4e2a7d9c1176affa72bce1bc", 111 | "type": "gitlab" 112 | }, 113 | "original": { 114 | "host": "gitlab.freedesktop.org", 115 | "owner": "wlroots", 116 | "repo": "wlroots", 117 | "rev": "3406c1b17a4a7e6d4e2a7d9c1176affa72bce1bc", 118 | "type": "gitlab" 119 | } 120 | }, 121 | "xdph": { 122 | "inputs": { 123 | "hyprland-protocols": [ 124 | "hyprland", 125 | "hyprland-protocols" 126 | ], 127 | "nixpkgs": [ 128 | "hyprland", 129 | "nixpkgs" 130 | ], 131 | "systems": [ 132 | "hyprland", 133 | "systems" 134 | ] 135 | }, 136 | "locked": { 137 | "lastModified": 1694628480, 138 | "narHash": "sha256-Qg9hstRw0pvjGu5hStkr2UX1D73RYcQ9Ns/KnZMIm9w=", 139 | "owner": "hyprwm", 140 | "repo": "xdg-desktop-portal-hyprland", 141 | "rev": "8f45a6435069b9e24ebd3160eda736d7a391cbf2", 142 | "type": "github" 143 | }, 144 | "original": { 145 | "owner": "hyprwm", 146 | "repo": "xdg-desktop-portal-hyprland", 147 | "type": "github" 148 | } 149 | } 150 | }, 151 | "root": "root", 152 | "version": 7 153 | } 154 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | hyprland.url = "github:hyprwm/Hyprland"; 4 | nix-filter.url = "github:numtide/nix-filter"; 5 | }; 6 | outputs = { self, hyprland, nix-filter, ... }: 7 | let 8 | inherit (hyprland.inputs) nixpkgs; 9 | forHyprlandSystems = fn: nixpkgs.lib.genAttrs (builtins.attrNames hyprland.packages) (system: fn system nixpkgs.legacyPackages.${system}); 10 | in 11 | { 12 | packages = forHyprlandSystems 13 | (system: pkgs: rec { 14 | hyprfocus = pkgs.gcc13Stdenv.mkDerivation { 15 | pname = "hyprfocus"; 16 | version = "0.1"; 17 | src = nix-filter.lib { 18 | root = ./.; 19 | include = [ 20 | "src" 21 | ./Makefile 22 | ]; 23 | }; 24 | 25 | 26 | nativeBuildInputs = with pkgs; [ pkg-config ]; 27 | 28 | buildInputs = with pkgs; [ 29 | hyprland.packages.${system}.hyprland.dev 30 | ] 31 | ++ hyprland.packages.${system}.hyprland.buildInputs; 32 | 33 | installPhase = '' 34 | mkdir -p $out/lib 35 | install ./hyprfocus.so $out/lib/libhyprfocus.so 36 | ''; 37 | 38 | meta = with pkgs.lib; { 39 | homepage = "https://github.com/VortexCoyote/hyprfocus"; 40 | description = "a focus animation plugin for Hyprland inspired by Flashfocus"; 41 | license = licenses.bsd3; 42 | platforms = platforms.linux; 43 | }; 44 | 45 | 46 | }; 47 | default = hyprfocus; 48 | }); 49 | }; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /flash.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VortexCoyote/hyprfocus/2eef8cfca879ccc8cc83f3dd7ac1dd012b5454ae/flash.gif -------------------------------------------------------------------------------- /hyprload.toml: -------------------------------------------------------------------------------- 1 | [hyprfocus] 2 | description = "a plugin which provides focus animations for us borderless folks, originally inspired by flashfocus" 3 | version = "2.0" 4 | author = "Vortex" 5 | 6 | [hyprfocus.build] 7 | output = "hyprfocus.so" 8 | steps = [ 9 | "make all", 10 | ] 11 | -------------------------------------------------------------------------------- /shrink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VortexCoyote/hyprfocus/2eef8cfca879ccc8cc83f3dd7ac1dd012b5454ae/shrink.gif -------------------------------------------------------------------------------- /src/Flash.cpp: -------------------------------------------------------------------------------- 1 | #include "Flash.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void CFlash::init(HANDLE pHandle, std::string animationName) { 9 | IFocusAnimation::init(pHandle, animationName); 10 | addConfigValue(pHandle, "flash_opacity", SConfigValue{.floatValue = 0.5f}); 11 | } 12 | 13 | void CFlash::onWindowFocus(CWindow* pWindow, HANDLE pHandle) { 14 | IFocusAnimation::onWindowFocus(pWindow, pHandle); 15 | 16 | pWindow->m_fAlpha = getConfigValue(pHandle, "flash_opacity")->floatValue; 17 | pWindow->m_fAlpha.setConfig(&m_sFocusInAnimConfig); 18 | pWindow->m_fAlpha.setCallbackOnEnd([this, pWindow, pHandle](void*) { 19 | //Make sure we restore to the active window opacity 20 | pWindow->m_fAlpha = HyprlandAPI::getConfigValue(pHandle, "decoration:active_opacity")->floatValue; 21 | pWindow->m_fAlpha.setConfig(&m_sFocusOutAnimConfig); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /src/Flash.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IFocusAnimation.hpp" 4 | 5 | class CFlash : public IFocusAnimation { 6 | public: 7 | void onWindowFocus(CWindow* pWindow, HANDLE pHandle) override; 8 | void init(HANDLE pHandle, std::string animationName) override; 9 | }; 10 | -------------------------------------------------------------------------------- /src/IFocusAnimation.cpp: -------------------------------------------------------------------------------- 1 | #include "IFocusAnimation.hpp" 2 | 3 | #include 4 | 5 | void IFocusAnimation::init(HANDLE pHandle, std::string animationName) { 6 | m_szAnimationName = animationName; 7 | 8 | HyprlandAPI::addConfigValue(pHandle, configPrefix() + "in_bezier", SConfigValue{.strValue = "default"}); 9 | HyprlandAPI::addConfigValue(pHandle, configPrefix() + "out_bezier", SConfigValue{.strValue = "default"}); 10 | 11 | HyprlandAPI::addConfigValue(pHandle, configPrefix() + "in_speed", SConfigValue{.floatValue = 1.f}); 12 | HyprlandAPI::addConfigValue(pHandle, configPrefix() + "out_speed", SConfigValue{.floatValue = 5.f}); 13 | 14 | m_sFocusInAnimConfig = *(g_pConfigManager->getAnimationPropertyConfig("global")); 15 | m_sFocusInAnimConfig.internalEnabled = 1; 16 | m_sFocusInAnimConfig.internalStyle = std::string("hyprfocus_") + animationName + std::string("_in"); 17 | m_sFocusInAnimConfig.pValues = &m_sFocusInAnimConfig; 18 | 19 | m_sFocusOutAnimConfig = *(g_pConfigManager->getAnimationPropertyConfig("global")); 20 | m_sFocusOutAnimConfig.internalEnabled = 1; 21 | m_sFocusOutAnimConfig.internalStyle = std::string("hyprfocus_") + animationName + std::string("_out"); 22 | m_sFocusOutAnimConfig.pValues = &m_sFocusOutAnimConfig; 23 | } 24 | 25 | void IFocusAnimation::onWindowFocus(CWindow* pWindow, HANDLE pHandle) { 26 | m_sFocusInAnimConfig.internalBezier = HyprlandAPI::getConfigValue(pHandle, configPrefix() + "in_bezier")->strValue; 27 | m_sFocusInAnimConfig.internalSpeed = HyprlandAPI::getConfigValue(pHandle, configPrefix() + "in_speed")->floatValue; 28 | 29 | m_sFocusOutAnimConfig.internalBezier = HyprlandAPI::getConfigValue(pHandle, configPrefix() + "out_bezier")->strValue; 30 | m_sFocusOutAnimConfig.internalSpeed = HyprlandAPI::getConfigValue(pHandle, configPrefix() + "out_speed")->floatValue; 31 | } 32 | 33 | void IFocusAnimation::addConfigValue(HANDLE pHandle, std::string name, SConfigValue sValue) { 34 | HyprlandAPI::addConfigValue(pHandle, configPrefix() + name, sValue); 35 | } 36 | 37 | SConfigValue* IFocusAnimation::getConfigValue(HANDLE pHandle, std::string name) { 38 | return HyprlandAPI::getConfigValue(pHandle, configPrefix() + name); 39 | } 40 | -------------------------------------------------------------------------------- /src/IFocusAnimation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WLR_USE_UNSTABLE 4 | 5 | #include 6 | 7 | class IFocusAnimation { 8 | public: 9 | virtual void onWindowFocus(CWindow* pWindow, HANDLE pHandle); 10 | virtual void init (HANDLE pHandle, std::string animationName); 11 | 12 | void addConfigValue(HANDLE pHandle, std::string name, SConfigValue sValue); 13 | SConfigValue* getConfigValue(HANDLE pHandle, std::string name); 14 | 15 | public: 16 | SAnimationPropertyConfig m_sFocusInAnimConfig; 17 | SAnimationPropertyConfig m_sFocusOutAnimConfig; 18 | 19 | std::string m_szAnimationName; 20 | 21 | std::string configPrefix() { return std::string("plugin:hyprfocus:") + m_szAnimationName + ":"; } 22 | }; 23 | -------------------------------------------------------------------------------- /src/Shrink.cpp: -------------------------------------------------------------------------------- 1 | #include "Shrink.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void CShrink::init(HANDLE pHandle, std::string animationName) { 9 | IFocusAnimation::init(pHandle, "shrink"); 10 | addConfigValue(pHandle, "shrink_percentage", SConfigValue{.floatValue = 0.5f}); 11 | } 12 | 13 | void CShrink::onWindowFocus(CWindow* pWindow, HANDLE pHandle) { 14 | std::string currentAnimStyle = pWindow->m_vRealSize.getConfig()->internalStyle; 15 | if ((currentAnimStyle == "popout" || currentAnimStyle == "popin") && pWindow->m_vRealSize.isBeingAnimated()) 16 | return; 17 | 18 | IFocusAnimation::onWindowFocus(pWindow, pHandle); 19 | 20 | const auto SHRINKPERCENTAGE = getConfigValue(pHandle, "shrink_percentage")->floatValue; 21 | 22 | pWindow->m_vRealSize.setConfig(&m_sFocusOutAnimConfig); 23 | pWindow->m_vRealPosition.setConfig(&m_sFocusOutAnimConfig); 24 | 25 | m_sShrinkAnimation.registerVar(); 26 | m_sShrinkAnimation.create(AVARTYPE_FLOAT, 1.0f, &m_sFocusInAnimConfig, pWindow, AVARDAMAGE_ENTIRE); 27 | m_sShrinkAnimation = SHRINKPERCENTAGE; 28 | 29 | m_sShrinkAnimation.setUpdateCallback([this, pWindow](void* pShrinkAnimation) { 30 | const auto GOALPOS = pWindow->m_vRealPosition.goalv(); 31 | const auto GOALSIZE = pWindow->m_vRealSize.goalv(); 32 | 33 | const auto* PANIMATION = (CAnimatedVariable*)pShrinkAnimation; 34 | 35 | pWindow->m_vRealSize.setValue(GOALSIZE * PANIMATION->fl()); 36 | pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.vec() / 2.f); 37 | }); 38 | 39 | m_sShrinkAnimation.setCallbackOnEnd([this, pWindow](void* pShrinkAnimation) { 40 | ((CAnimatedVariable*)pShrinkAnimation)->resetAllCallbacks(); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /src/Shrink.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IFocusAnimation.hpp" 4 | 5 | class CShrink : public IFocusAnimation { 6 | public: 7 | void onWindowFocus(CWindow* pWindow, HANDLE pHandle) override; 8 | void init(HANDLE pHandle, std::string animationName) override; 9 | 10 | CAnimatedVariable m_sShrinkAnimation; 11 | }; 12 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #define WLR_USE_UNSTABLE 2 | 3 | #include 4 | 5 | inline HANDLE PHANDLE = nullptr; 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "Flash.hpp" 12 | #include "Shrink.hpp" 13 | 14 | #include 15 | 16 | CWindow* g_pPreviouslyFocusedWindow = nullptr; 17 | bool g_bMouseWasPressed = false; 18 | 19 | std::unordered_map> g_mAnimations; 20 | 21 | void flashWindow(CWindow* pWindow) { 22 | auto* const PTYPE = g_bMouseWasPressed ? &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprfocus:mouse_focus_animation")->strValue 23 | : &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprfocus:keyboard_focus_animation")->strValue; 24 | 25 | g_mAnimations[*PTYPE]->onWindowFocus(pWindow, PHANDLE); 26 | } 27 | 28 | void flashCurrentWindow(std::string) { 29 | static auto* const PHYPRFOCUSENABLED = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprfocus:enabled")->intValue; 30 | 31 | if (!*PHYPRFOCUSENABLED) 32 | return; 33 | 34 | if(g_pPreviouslyFocusedWindow == nullptr) 35 | return; 36 | 37 | flashWindow(g_pPreviouslyFocusedWindow); 38 | } 39 | 40 | static void onActiveWindowChange(void* self, std::any data) { 41 | try { 42 | auto* const PWINDOW = std::any_cast(data); 43 | static auto* const PHYPRFOCUSENABLED = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprfocus:enabled")->intValue; 44 | 45 | if (!*PHYPRFOCUSENABLED) 46 | return; 47 | 48 | if(PWINDOW == nullptr) 49 | return; 50 | 51 | if(PWINDOW == g_pPreviouslyFocusedWindow) 52 | return; 53 | 54 | flashWindow(PWINDOW); 55 | g_pPreviouslyFocusedWindow = PWINDOW; 56 | 57 | } catch (std::bad_any_cast& e) { } 58 | } 59 | 60 | static void onMouseButton(void* self, std::any data) { 61 | try { 62 | auto* const PWLRMOUSEBUTTONEVENT = std::any_cast(data); 63 | g_bMouseWasPressed = PWLRMOUSEBUTTONEVENT->state == WLR_BUTTON_PRESSED; 64 | 65 | } catch (std::bad_any_cast& e) { } 66 | } 67 | 68 | // Do NOT change this function. 69 | APICALL EXPORT std::string PLUGIN_API_VERSION() { 70 | return HYPRLAND_API_VERSION; 71 | } 72 | 73 | APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { 74 | PHANDLE = handle; 75 | 76 | HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprfocus:enabled", SConfigValue{.intValue = 0 }); 77 | HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprfocus:keyboard_focus_animation", SConfigValue{.strValue = "flash"}); 78 | HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprfocus:mouse_focus_animation", SConfigValue{.strValue = "flash"}); 79 | 80 | HyprlandAPI::addDispatcher(PHANDLE, "animatefocused", &flashCurrentWindow); 81 | 82 | g_mAnimations["flash" ] = std::make_unique(); 83 | g_mAnimations["shrink" ] = std::make_unique(); 84 | g_mAnimations["nothing" ] = std::make_unique(); 85 | 86 | for(auto& [name, pAnimation] : g_mAnimations) { 87 | pAnimation->init(PHANDLE, name); 88 | } 89 | 90 | HyprlandAPI::reloadConfig(); 91 | 92 | HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, SCallbackInfo& info, std::any data) { onActiveWindowChange(self, data); }); 93 | HyprlandAPI::registerCallbackDynamic(PHANDLE, "mouseButton", [&](void* self, SCallbackInfo& info, std::any data) { onMouseButton (self, data); }); 94 | 95 | return {"hyprfocus", "animate windows on focus", "Vortex", "2.0"}; 96 | } 97 | 98 | APICALL EXPORT void PLUGIN_EXIT() { } 99 | --------------------------------------------------------------------------------