├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── default.nix ├── flake.lock ├── flake.nix ├── hyprpm.toml ├── install.sh ├── meson.build └── src ├── OvGridLayout.cpp ├── OvGridLayout.hpp ├── dispatchers.cpp ├── dispatchers.hpp ├── globaleventhook.cpp ├── globaleventhook.hpp ├── globals.hpp ├── log.hpp └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /result 2 | /build 3 | /.vscode 4 | /.cache -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(Hycov VERSION "0.2") 3 | set(CMAKE_CXX_STANDARD 23) 4 | add_compile_definitions(WLR_USE_UNSTABLE) 5 | add_compile_options(-g -Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith) 6 | 7 | # nix workaround 8 | if(CMAKE_EXPORT_COMPILE_COMMANDS) 9 | set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES 10 | ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) 11 | endif() 12 | 13 | find_package(PkgConfig REQUIRED) 14 | pkg_check_modules(DEPS REQUIRED hyprland pixman-1 libdrm pango pangocairo) 15 | 16 | add_library(hycov SHARED 17 | src/main.cpp 18 | src/dispatchers.cpp 19 | src/OvGridLayout.cpp 20 | src/globaleventhook.cpp 21 | ) 22 | 23 | target_include_directories(hycov PRIVATE ${DEPS_INCLUDE_DIRS}) 24 | 25 | install(TARGETS hycov LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) 26 | 27 | # set(CMAKE_VERBOSE_MAKEFILE ON) 28 | # set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 GreamMaoMao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hycov 2 | A Hyprland overview mode plugin, a new tiling WM workflow. 3 | 4 | > [!NOTE] 5 | > This repository only maintains the hyprland version corresponding to each hycov release, please do not bring up the issue of non-release versions, because I do not have enough time to track every commit. 6 | 7 | ### What can it do? 8 | - Hycov can tile all of your windows in a single workspace via grid layout. 9 | 10 | - After quitting the overview mode, hycov can perfectly recover a window's previous state (fullscreen, floating, size, positon, etc.) 11 | 12 | - Hycov supports a variety of trigger methods, such as touch pad gestures, hot corners, and keyboard shortcuts. 13 | 14 | - Supports multiple monitors. 15 | 16 | - You can change the way that Hycov focuses a window, whether directional or cyclical. (single-shortcut) 17 | 18 | https://github.com/DreamMaoMao/hycov/assets/30348075/59121362-21a8-4143-be95-72ce79ee8e95 19 | 20 | 21 | Anyone is welcome to fork. If you end up improving the plugin, please let me know, and I'll be happy to use your fork. 22 | 23 | ### Manual Installation 24 | 25 | > [!NOTE] 26 | > 1. After Hycov is installed, you will need to logout, then log back in. This may happen automatically, but do not worry. This behaviour is normal. 27 | > 2. Only supports hyprland source code after 2023-10-22, because the plugin requires this [commit](https://github.com/hyprwm/Hyprland/commit/a61eb7694df25a75f45502ed64b1536fda370c1d) in [hyprland](https://github.com/hyprwm/Hyprland). 28 | > 3. Each release of hycov corresponds to each release of hyprland. If you are using a release version of hycov, but you are using the latest hyprland-git, this may not be available. 29 | 30 | ##### Using meson and ninja: 31 | 32 | ```shell 33 | git clone https://github.com/DreamMaoMao/hycov.git 34 | cd hycov 35 | sudo meson setup build --prefix=/usr 36 | sudo ninja -C build 37 | sudo ninja -C build install # `libhycov.so` path: /usr/lib/libhycov.so 38 | ``` 39 | 40 | ##### Using CMake: 41 | 42 | ```shell 43 | git clone https://github.com/DreamMaoMao/hycov.git 44 | cd hycov 45 | bash install.sh # `libhycov.so` path: /usr/lib/libhycov.so 46 | ``` 47 | 48 | ##### Using hyprpm: 49 | 50 | ```shell 51 | hyprpm update 52 | hyprpm add https://github.com/DreamMaoMao/hycov 53 | hyprpm enable hycov 54 | ``` 55 | 56 | ### Usage (hyprland.conf) 57 | 58 | ```conf 59 | # When entering overview mode, you can use left-button to jump, right-button to kill or use keybind 60 | 61 | # If you are installing hycov with hyprpm, you should comment out this 62 | plugin = /usr/lib/libhycov.so 63 | 64 | # If you are installing hycov by manually compile , you should comment out this 65 | exec-once = hyprpm reload 66 | 67 | # bind key to toggle overview (normal) 68 | bind = ALT,tab,hycov:toggleoverview 69 | 70 | # bind key to toggle overview (force mode, not affected by `only_active_workspace` or `only_active_monitor`) 71 | bind = ALT,grave,hycov:toggleoverview,forceall #grave key is the '~' key 72 | 73 | # bind key to toggle overview (force mode, not affected by `only_active_workspace` or `only_active_monitor`) 74 | bind = ALT,c,hycov:toggleoverview,onlycurrentworkspace 75 | 76 | # bind key to toggle overview (shows all windows in one monitor, not affected by `only_active_workspace` or `only_active_monitor`) 77 | bind = ALT,g,hycov:toggleoverview,forceallinone 78 | 79 | # The key binding for directional switch mode. 80 | # Calculate the window closest to the direction to switch focus. 81 | # This keybind is applicable not only to the overview, but also to the general layout. 82 | bind=ALT,left,hycov:movefocus,l 83 | bind=ALT,right,hycov:movefocus,r 84 | bind=ALT,up,hycov:movefocus,u 85 | bind=ALT,down,hycov:movefocus,d 86 | 87 | # if you want that focusmove can cross monitor, use this 88 | bind=ALT,left,hycov:movefocus,leftcross 89 | bind=ALT,right,hycov:movefocus,rightcross 90 | bind=ALT,up,hycov:movefocus,upcross 91 | bind=ALT,down,hycov:movefocus,downcross 92 | 93 | plugin { 94 | hycov { 95 | overview_gappo = 60 # gaps width from screen edge 96 | overview_gappi = 24 # gaps width from clients 97 | enable_hotarea = 1 # enable mouse cursor hotarea, when cursor enter hotarea, it will toggle overview 98 | enable_click_action = 1 # enable mouse left button jump and right button kill in overview mode 99 | hotarea_monitor = all # monitor name which hotarea is in, default is all 100 | hotarea_pos = 1 # position of hotarea (1: bottom left, 2: bottom right, 3: top left, 4: top right) 101 | hotarea_size = 10 # hotarea size, 10x10 102 | swipe_fingers = 4 # finger number of gesture,move any directory 103 | move_focus_distance = 100 # distance for movefocus,only can use 3 finger to move 104 | enable_gesture = 0 # enable gesture 105 | auto_exit = 1 # enable auto exit when no client in overview 106 | auto_fullscreen = 0 # auto make active window maximize after exit overview 107 | only_active_workspace = 0 # only overview the active workspace 108 | only_active_monitor = 0 # only overview the active monitor 109 | enable_alt_release_exit = 0 # alt swith mode arg,see readme for detail 110 | alt_replace_key = Alt_L # alt swith mode arg,see readme for detail 111 | alt_toggle_auto_next = 0 # auto focus next window when toggle overview in alt swith mode 112 | click_in_cursor = 1 # when click to jump,the target windwo is find by cursor, not the current foucus window. 113 | hight_of_titlebar = 0 # height deviation of title bar height 114 | show_special = 0 # show windwos in special workspace in overview. 115 | raise_float_to_top = 1 # raise the window that is floating before to top after leave overview mode 116 | } 117 | } 118 | 119 | ``` 120 | 121 | # suggested additional configuration 122 | - when `auto_fullscreen=1` is set, you can also set the border color to mark the maximize state and bind key to control fullscreen maximize state. 123 | ``` 124 | windowrulev2 = bordercolor rgb(158833),fullscreen:1 # set bordercolor to green if window is fullscreen maximize 125 | # toggle fullscreen maximize 126 | bind = ALT,a,fullscreen,1 127 | ``` 128 |
129 | detail video 130 | 131 | https://github.com/DreamMaoMao/hycov/assets/30348075/15ba36c2-1782-4ae0-8ac1-d0ca98e01e0f 132 | 133 |
134 | 135 | 136 | - if you use the `hyprland/workspaces` module in waybar,you should change field {id} to {name}. It will let you know you are in overview mode. 137 | ``` 138 | "hyprland/workspaces": { 139 | "format": "{name}", 140 | "on-click":"activate", 141 | }, 142 | ``` 143 | 144 |
145 | detail picture 146 | 147 | ![image](https://github.com/DreamMaoMao/hycov/assets/30348075/332f4025-20c1-4a44-853b-1b5264df986e) 148 | ![image](https://github.com/DreamMaoMao/hycov/assets/30348075/500d9fd7-299b-48bc-ab72-146f263044a5) 149 | 150 |
151 | 152 | 153 | # Alt switch mode 154 | ```conf 155 | enable_alt_release_exit = 1 156 | alt_toggle_auto_next = 0 # auto focus next window when enter overview in alt mode 157 | # alt_replace_key = Alt_L # If your MainKey of toggleoverview is ALt, you can ignore it 158 | ``` 159 | ## operation 160 | such as `alt + tab`: 161 | 162 | - 1.`alt + tab` will enter overview when you not in overview(please hold alt,don't make it release) 163 | 164 | - 2.`alt + tab` will switch window focus circularly when you in overview. (please hold alt,don't make it release) 165 | 166 | - 3.when you release `alt` , it will auto exit overview. 167 | 168 |
169 | If you don't want to use `alt` as MainKey in alt mode 170 | 171 | such as use `super` to repalce `alt` 172 | - 1.bind toggleoverview 173 | ``` 174 | bind = SUPER,tab,hycov:toggleoverview 175 | ``` 176 | - 2.use `alt_replace_key` to specify what is the detection key on release. 177 | ``` 178 | # use keyname 179 | alt_replace_key = Super_L # Alt_L,Alt_R,Super_L,Super_R,Control_L,Control_R,Shift_L,Shift_R 180 | 181 | # use keycode 182 | alt_replace_key = code:133 # use `xev` command to get keycode 183 | ``` 184 | 185 |
186 | 187 | ### NixOS with home—manager 188 | 189 | ```nix 190 | # flake.nix 191 | 192 | { 193 | inputs = { 194 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 195 | 196 | home-manager = { 197 | url = "github:nix-community/home-manager"; 198 | inputs.nixpkgs.follows = "nixpkgs"; 199 | }; 200 | 201 | hyprland.url = "github:hyprwm/Hyprland"; 202 | 203 | hycov={ 204 | url = "github:DreamMaoMao/hycov"; 205 | inputs.hyprland.follows = "hyprland"; 206 | }; 207 | }; 208 | 209 | outputs = { nixpkgs, home-manager, hyprland, hycov, ... }: 210 | let 211 | system = "x86_64-linux"; 212 | pkgs = nixpkgs.legacyPackages.${system}; 213 | in 214 | { 215 | homeConfigurations."user@hostname" = home-manager.lib.homeManagerConfiguration { 216 | pkgs = nixpkgs.legacyPackages.x86_64-linux; 217 | 218 | modules = [ 219 | hyprland.homeManagerModules.default 220 | { 221 | wayland.windowManager.hyprland = { 222 | enable = true; 223 | package = hyprland.packages."${pkgs.system}".hyprland; 224 | plugins = [ 225 | hycov.packages.${pkgs.system}.hycov 226 | ]; 227 | extraConfig = '' 228 | bind = ALT,tab,hycov:toggleoverview 229 | bind=ALT,left,hycov:movefocus,l 230 | bind=ALT,right,hycov:movefocus,r 231 | bind=ALT,up,hycov:movefocus,u 232 | bind=ALT,down,hycov:movefocus,d 233 | 234 | plugin { 235 | hycov { 236 | overview_gappo = 60 #gaps width from screen 237 | overview_gappi = 24 #gaps width from clients 238 | hotarea_size = 10 #hotarea size in bottom left,10x10 239 | enable_hotarea = 1 # enable mouse cursor hotarea 240 | } 241 | } 242 | '' + '' 243 | # your othor config 244 | ''; 245 | }; 246 | } 247 | # ... 248 | ]; 249 | }; 250 | }; 251 | } 252 | ``` 253 | ## Frequently Asked Questions 254 | - some config not work, or the plugin not work. 255 | ``` 256 | if you use install hycov at first time,please try logout and relogin again. 257 | ``` 258 | 259 | - The numbers on the waybar are confused 260 | 261 | ``` 262 | 1.Please pull the latest waybar source code compilation, 263 | this issue has been fixed in the waybar project, fix date (2023-10-27) 264 | 265 | 2.Change the {id} field in hyprland/workspace field to {name} 266 | ``` 267 | 268 | - Compilation failure 269 | ``` 270 | Please pull the latest hyprland source code to compile and install. 271 | The plugin relies on a hyprland pr,pr submission date (2023-10-21) 272 | ``` 273 | 274 | - Unable to load 275 | ``` 276 | Check whether hyprland has been updated, 277 | and if so, please recompile hyprcov 278 | ``` 279 | 280 | - build fail with message `No such file or directory #include ` 281 | ``` 282 | #step1 283 | yay -R hyprland-git wlroots-git 284 | 285 | #step2 286 | sudo rm -rf /usr/include/hyprland 287 | sudo rm -rf /usr/include/wlr 288 | sudo rm -rf/usr/local/include/hyprland 289 | sudo rm -rf /usr/local/include/wlr 290 | 291 | #step3 292 | yay -S wlroots-git hyprland-git 293 | ``` 294 | 295 | 296 | ## Some cool use cases 297 |
298 | hycov + [hyprland-easymotion](https://github.com/zakk4223/hyprland-easymotion) 299 | 300 | 301 | https://github.com/DreamMaoMao/hycov/assets/30348075/486b08f1-be0d-4647-90a3-2029961402cd 302 | 303 | 304 | ```conf 305 | bind = ALT,tab, exec, ~/.config/hypr/scripts/hycov-easymotion.sh 306 | submap=__easymotionsubmap__ 307 | bind = ALT, Tab, exec, ~/.config/hypr/scripts/hycov-easymotion.sh 308 | submap=reset 309 | ``` 310 | 311 | ```bash 312 | #!/bin/bash 313 | 314 | workspace_name=$(hyprctl -j activeworkspace | jq -r '.name') 315 | 316 | if [ "$workspace_name" = "OVERVIEW" ]; then 317 | hyprctl dispatch hycov:leaveoverview 318 | else 319 | hyprctl dispatch hycov:enteroverview 320 | hyprctl dispatch 'easymotion action:hyprctl --batch "dispatch focuswindow address:{} ; dispatch hycov:leaveoverview"' 321 | fi 322 | ``` 323 | 324 |
325 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , stdenv 3 | , hyprland 4 | }: 5 | stdenv.mkDerivation { 6 | pname = "hycov"; 7 | version = "0.2"; 8 | src = ./.; 9 | 10 | inherit (hyprland) nativeBuildInputs; 11 | 12 | buildInputs = [ hyprland ] ++ hyprland.buildInputs; 13 | 14 | meta = with lib; { 15 | homepage = "https://github.com/DreamMaoMao/hycov"; 16 | description = "clients overview for hyprland plugin"; 17 | license = licenses.mit; 18 | platforms = platforms.linux; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "hyprcursor": { 4 | "inputs": { 5 | "hyprlang": [ 6 | "hyprland", 7 | "hyprlang" 8 | ], 9 | "nixpkgs": [ 10 | "hyprland", 11 | "nixpkgs" 12 | ], 13 | "systems": [ 14 | "hyprland", 15 | "systems" 16 | ] 17 | }, 18 | "locked": { 19 | "lastModified": 1717181720, 20 | "narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=", 21 | "owner": "hyprwm", 22 | "repo": "hyprcursor", 23 | "rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c", 24 | "type": "github" 25 | }, 26 | "original": { 27 | "owner": "hyprwm", 28 | "repo": "hyprcursor", 29 | "type": "github" 30 | } 31 | }, 32 | "hyprland": { 33 | "inputs": { 34 | "hyprcursor": "hyprcursor", 35 | "hyprlang": "hyprlang", 36 | "hyprwayland-scanner": "hyprwayland-scanner", 37 | "nixpkgs": "nixpkgs", 38 | "systems": "systems", 39 | "xdph": "xdph" 40 | }, 41 | "locked": { 42 | "lastModified": 1717970802, 43 | "narHash": "sha256-kFnaAmte/N1mrbHEQyrwDu9+laZzVAi4N2nQodCNfgg=", 44 | "ref": "refs/heads/main", 45 | "rev": "1423707dbefc0329e80895451903a77ab684f7ea", 46 | "revCount": 4789, 47 | "submodules": true, 48 | "type": "git", 49 | "url": "https://github.com/hyprwm/Hyprland" 50 | }, 51 | "original": { 52 | "submodules": true, 53 | "type": "git", 54 | "url": "https://github.com/hyprwm/Hyprland" 55 | } 56 | }, 57 | "hyprland-protocols": { 58 | "inputs": { 59 | "nixpkgs": [ 60 | "hyprland", 61 | "xdph", 62 | "nixpkgs" 63 | ], 64 | "systems": [ 65 | "hyprland", 66 | "xdph", 67 | "systems" 68 | ] 69 | }, 70 | "locked": { 71 | "lastModified": 1691753796, 72 | "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", 73 | "owner": "hyprwm", 74 | "repo": "hyprland-protocols", 75 | "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", 76 | "type": "github" 77 | }, 78 | "original": { 79 | "owner": "hyprwm", 80 | "repo": "hyprland-protocols", 81 | "type": "github" 82 | } 83 | }, 84 | "hyprlang": { 85 | "inputs": { 86 | "nixpkgs": [ 87 | "hyprland", 88 | "nixpkgs" 89 | ], 90 | "systems": [ 91 | "hyprland", 92 | "systems" 93 | ] 94 | }, 95 | "locked": { 96 | "lastModified": 1716473782, 97 | "narHash": "sha256-+qLn4lsHU6iL3+HTo1gTQ1tWzet8K9h+IfVemzEQZj8=", 98 | "owner": "hyprwm", 99 | "repo": "hyprlang", 100 | "rev": "87d5d984109c839482b88b4795db073eb9ed446f", 101 | "type": "github" 102 | }, 103 | "original": { 104 | "owner": "hyprwm", 105 | "repo": "hyprlang", 106 | "type": "github" 107 | } 108 | }, 109 | "hyprwayland-scanner": { 110 | "inputs": { 111 | "nixpkgs": [ 112 | "hyprland", 113 | "nixpkgs" 114 | ], 115 | "systems": [ 116 | "hyprland", 117 | "systems" 118 | ] 119 | }, 120 | "locked": { 121 | "lastModified": 1717784906, 122 | "narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=", 123 | "owner": "hyprwm", 124 | "repo": "hyprwayland-scanner", 125 | "rev": "0f30f9eca6e404130988554accbb64d1c9ec877d", 126 | "type": "github" 127 | }, 128 | "original": { 129 | "owner": "hyprwm", 130 | "repo": "hyprwayland-scanner", 131 | "type": "github" 132 | } 133 | }, 134 | "nixpkgs": { 135 | "locked": { 136 | "lastModified": 1717602782, 137 | "narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", 138 | "owner": "NixOS", 139 | "repo": "nixpkgs", 140 | "rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", 141 | "type": "github" 142 | }, 143 | "original": { 144 | "owner": "NixOS", 145 | "ref": "nixos-unstable", 146 | "repo": "nixpkgs", 147 | "type": "github" 148 | } 149 | }, 150 | "root": { 151 | "inputs": { 152 | "hyprland": "hyprland", 153 | "nixpkgs": [ 154 | "hyprland", 155 | "nixpkgs" 156 | ], 157 | "systems": [ 158 | "hyprland", 159 | "systems" 160 | ] 161 | } 162 | }, 163 | "systems": { 164 | "locked": { 165 | "lastModified": 1689347949, 166 | "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", 167 | "owner": "nix-systems", 168 | "repo": "default-linux", 169 | "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", 170 | "type": "github" 171 | }, 172 | "original": { 173 | "owner": "nix-systems", 174 | "repo": "default-linux", 175 | "type": "github" 176 | } 177 | }, 178 | "xdph": { 179 | "inputs": { 180 | "hyprland-protocols": "hyprland-protocols", 181 | "hyprlang": [ 182 | "hyprland", 183 | "hyprlang" 184 | ], 185 | "nixpkgs": [ 186 | "hyprland", 187 | "nixpkgs" 188 | ], 189 | "systems": [ 190 | "hyprland", 191 | "systems" 192 | ] 193 | }, 194 | "locked": { 195 | "lastModified": 1716290197, 196 | "narHash": "sha256-1u9Exrc7yx9qtES2brDh7/DDZ8w8ap1nboIOAtCgeuM=", 197 | "owner": "hyprwm", 198 | "repo": "xdg-desktop-portal-hyprland", 199 | "rev": "91e48d6acd8a5a611d26f925e51559ab743bc438", 200 | "type": "github" 201 | }, 202 | "original": { 203 | "owner": "hyprwm", 204 | "repo": "xdg-desktop-portal-hyprland", 205 | "type": "github" 206 | } 207 | } 208 | }, 209 | "root": "root", 210 | "version": 7 211 | } 212 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Hyprland Plugins (Hycov)"; 3 | 4 | inputs = { 5 | hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1"; 6 | nixpkgs.follows = "hyprland/nixpkgs"; 7 | systems.follows = "hyprland/systems"; 8 | }; 9 | 10 | outputs = 11 | { self 12 | , hyprland 13 | , nixpkgs 14 | , systems 15 | }: 16 | let 17 | inherit (nixpkgs) lib; 18 | withPkgsFor = fn: lib.genAttrs (import systems) (system: 19 | let 20 | pkgs = import nixpkgs { 21 | localSystem.system = system; 22 | overlays = [ 23 | hyprland.overlays.hyprland-packages 24 | self.overlays.default 25 | ]; 26 | }; 27 | in 28 | fn system pkgs); 29 | in 30 | { 31 | overlays = { 32 | default = self.overlays.hycov; 33 | hycov = final: prev: { 34 | hyprlandPlugins = prev.hyprlandPlugins or {} // { 35 | hycov = final.callPackage ./default.nix { 36 | stdenv = final.gcc13Stdenv; 37 | }; 38 | }; 39 | }; 40 | }; 41 | 42 | packages = withPkgsFor (system: pkgs: { 43 | default = self.packages.${system}.hycov; 44 | inherit (pkgs.hyprlandPlugins) hycov; 45 | }); 46 | 47 | devShells = withPkgsFor (system: pkgs: { 48 | default = pkgs.mkShell.override { stdenv = pkgs.gcc13Stdenv; } { 49 | name = "hyprland-plugins"; 50 | # buildInputs = [ pkgs.hyprland ]; 51 | inputsFrom = [ pkgs.hycov ]; 52 | }; 53 | }); 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /hyprpm.toml: -------------------------------------------------------------------------------- 1 | [repository] 2 | name = "hycov" 3 | authors = ["DreamMaoMao"] 4 | commit_pins = [ 5 | ["03ebbe18ed8517ee22591eac82cd54322f42cb7d", "b14e35d8c08ca2e946b7249f9024c2b1787398e6"], 6 | ["cbadf3e3f31ab5ad5d192daac5f2ca930d08b8fb", "c5c314d2e4ca44011cc9f64f13ff9071eda751dd"], 7 | ["84ab8d11e8951a6551d1e1bf87796a8589da6d47", "06c3ec69171e1937a889bc20b84bbc33a70b4400"], 8 | ["13f6f0b923ff3ec94a3bec886c28b90402ceef91", "2c88820384c78b13ce92ef61fa0822369c9c6ecf"], 9 | ["1c460e98f870676b15871fe4e5bfeb1a32a3d6d8", "7d48cff8364a7b6ae52a3472ad1dfe01b9f728ae"], 10 | ["e93fbd7c4f991cb8ef03e433ccc4d43587923e15", "05fb15703d07a372b14a3260a337de13d1c16b91"], 11 | ["fe7b748eb668136dd0558b7c8279bfcd7ab4d759", "05fb15703d07a372b14a3260a337de13d1c16b91"], 12 | ["cba1ade848feac44b2eda677503900639581c3f4", "89fc3dc62d4aca3745d2b1aa6ab81dab541c232c"], 13 | ["ea2501d4556f84d3de86a4ae2f4b22a474555b9f", "7b1f51d005c5f477c763f1031b807787f2f6b449"], 14 | ["9e781040d9067c2711ec2e9f5b47b76ef70762b3","a1c4287c2ebb5f5596dc53571993725be9d63cb0"], 15 | ["918d8340afd652b011b937d29d5eea0be08467f5","a1c4287c2ebb5f5596dc53571993725be9d63cb0"] 16 | 17 | ] 18 | 19 | [hycov] 20 | description = "hyprland overview mode" 21 | authors = ["DreamMaoMao"] 22 | output = "build/libhycov.so" 23 | build = [ 24 | "cmake -DCMAKE_BUILD_TYPE=Release -B build", 25 | "cmake --build build -j $(nproc)" 26 | ] 27 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | sudo rm build/* -rf 2 | cmake -DCMAKE_BUILD_TYPE=Debug -B build 3 | cmake --build build -j $(nproc) 4 | sudo cp build/libhycov.so /usr/lib 5 | 6 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('hycov', 'cpp', 2 | version: '0.2', 3 | default_options: ['buildtype=release'], 4 | ) 5 | 6 | cpp_compiler = meson.get_compiler('cpp') 7 | if cpp_compiler.has_argument('-std=c++23') 8 | add_global_arguments('-std=c++23', language: 'cpp') 9 | elif cpp_compiler.has_argument('-std=c++2b') 10 | add_global_arguments('-std=c++2b', language: 'cpp') 11 | else 12 | error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') 13 | endif 14 | 15 | add_project_arguments( 16 | [ 17 | '-DWLR_USE_UNSTABLE', 18 | '-g', '-Wall', '-Wextra', '-Wno-unused-parameter', 19 | '-Wno-unused-value', '-Wno-missing-field-initializers', 20 | '-Wno-narrowing', '-Wno-pointer-arith', 21 | ], 22 | language: 'cpp') 23 | 24 | src = [ 25 | 'src/main.cpp', 26 | 'src/dispatchers.cpp', 27 | 'src/OvGridLayout.cpp', 28 | 'src/globaleventhook.cpp', 29 | ] 30 | 31 | shared_module(meson.project_name(), src, 32 | dependencies: [ 33 | dependency('hyprland'), 34 | dependency('pixman-1'), 35 | dependency('libdrm'), 36 | dependency('pango'), 37 | dependency('pangocairo') 38 | ], 39 | install: true, 40 | ) 41 | -------------------------------------------------------------------------------- /src/OvGridLayout.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "globals.hpp" 3 | #include "OvGridLayout.hpp" 4 | #include "dispatchers.hpp" 5 | 6 | // find next focus window after remove a window 7 | PHLWINDOW OvGridLayout::getNextWindowCandidate(PHLWINDOW plastWindow) { 8 | 9 | PHLWINDOW targetWindow = nullptr; 10 | for (auto &w : g_pCompositor->m_vWindows) 11 | { 12 | PHLWINDOW pWindow = w; 13 | if (pWindow->m_pWorkspace != plastWindow->m_pWorkspace || pWindow->isHidden() || !pWindow->m_bIsMapped || pWindow->m_bFadingOut || pWindow->m_bIsFullscreen) 14 | continue; 15 | targetWindow = pWindow; // find the last window that is in same workspace with the remove window 16 | } 17 | 18 | return targetWindow; 19 | 20 | } 21 | 22 | SOvGridNodeData *OvGridLayout::getNodeFromWindow(PHLWINDOW pWindow) 23 | { 24 | for (auto &nd : m_lOvGridNodesData) 25 | { 26 | if (nd.pWindow == pWindow) 27 | return &nd; 28 | } 29 | 30 | return nullptr; 31 | } 32 | 33 | 34 | SOldLayoutRecordNodeData *OvGridLayout::getOldLayoutRecordNodeFromWindow(PHLWINDOW pWindow) 35 | { 36 | for (auto &nd : m_lSOldLayoutRecordNodeData) 37 | { 38 | if (nd.pWindow == pWindow) 39 | return &nd; 40 | } 41 | 42 | return nullptr; 43 | } 44 | 45 | int OvGridLayout::getNodesNumOnWorkspace(const int &ws) 46 | { 47 | int no = 0; 48 | for (auto &n : m_lOvGridNodesData) 49 | { 50 | if (n.workspaceID == ws) 51 | no++; 52 | } 53 | 54 | return no; 55 | } 56 | 57 | 58 | Vector2D OvGridLayout::predictSizeForNewWindowTiled() { 59 | return {}; 60 | } 61 | 62 | void OvGridLayout::resizeNodeSizePos(SOvGridNodeData *node, int x, int y, int width, int height) 63 | { 64 | 65 | int groupbar_height_fix; 66 | if(node->pWindow->m_sGroupData.pNextWindow.lock()) { 67 | groupbar_height_fix = g_hycov_groupBarHeight; 68 | } else { 69 | groupbar_height_fix = 0; 70 | } 71 | node->size = Vector2D(width, height - g_hycov_height_of_titlebar - groupbar_height_fix); 72 | node->position = Vector2D(x, y + g_hycov_height_of_titlebar + groupbar_height_fix); 73 | applyNodeDataToWindow(node); 74 | } 75 | 76 | void OvGridLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection direction) 77 | { 78 | CMonitor *pTargetMonitor; 79 | if(g_hycov_forece_display_all_in_one_monitor) { 80 | pTargetMonitor = g_pCompositor->m_pLastMonitor.get(); 81 | } else { 82 | pTargetMonitor = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); 83 | } 84 | 85 | const auto pNode = &m_lOvGridNodesData.emplace_back(); // make a new node in list back 86 | 87 | auto pActiveWorkspace = pTargetMonitor->activeWorkspace; 88 | 89 | auto pWindowOriWorkspace = pWindow->m_pWorkspace; 90 | 91 | auto oldLayoutRecordNode = getOldLayoutRecordNodeFromWindow(pWindow); 92 | if(oldLayoutRecordNode) { 93 | pNode->isInOldLayout = true; //client is taken from the old layout 94 | m_lSOldLayoutRecordNodeData.remove(*oldLayoutRecordNode); 95 | } 96 | 97 | //record the previcous window in group 98 | if(pWindow->m_sGroupData.pNextWindow.lock() && pWindow->getGroupCurrent() == pWindow) { 99 | pNode->isGroupActive = true; 100 | } 101 | 102 | pNode->workspaceID = pWindow->m_pWorkspace->m_iID; // encapsulate window objects as node objects to bind more properties 103 | pNode->pWindow = pWindow; 104 | pNode->workspaceName = pWindowOriWorkspace->m_szName; 105 | 106 | //record the window stats which are used by restore 107 | pNode->ovbk_windowMonitorId = pWindow->m_iMonitorID; 108 | pNode->ovbk_windowWorkspaceId = pWindow->m_pWorkspace->m_iID; 109 | pNode->ovbk_windowFullscreenMode = pWindowOriWorkspace->m_efFullscreenMode; 110 | pNode->ovbk_position = pWindow->m_vRealPosition.goal(); 111 | pNode->ovbk_size = pWindow->m_vRealSize.goal(); 112 | pNode->ovbk_windowIsFloating = pWindow->m_bIsFloating; 113 | pNode->ovbk_windowIsFullscreen = pWindow->m_bIsFullscreen; 114 | pNode->ovbk_windowWorkspaceName = pWindowOriWorkspace->m_szName; 115 | 116 | //record the window style which are used by restore 117 | pNode->ovbk_windowIsWithBorder = pWindow->m_sSpecialRenderData.border; 118 | pNode->ovbk_windowIsWithDecorate = pWindow->m_sSpecialRenderData.decorate; 119 | pNode->ovbk_windowIsWithRounding = pWindow->m_sSpecialRenderData.rounding; 120 | pNode->ovbk_windowIsWithShadow = pWindow->m_sSpecialRenderData.shadow; 121 | 122 | 123 | //change all client(exclude special workspace) to active worksapce 124 | if ((!g_pCompositor->isWorkspaceSpecial(pNode->workspaceID) || g_hycov_show_special) && pNode->isInOldLayout && (pWindowOriWorkspace->m_iID != pActiveWorkspace->m_iID || pWindowOriWorkspace->m_szName != pActiveWorkspace->m_szName) && (!(g_hycov_only_active_workspace || g_hycov_force_display_only_current_workspace) || g_hycov_forece_display_all || g_hycov_forece_display_all_in_one_monitor)) { 125 | pWindow->m_pWorkspace = pActiveWorkspace; 126 | pNode->workspaceID = pWindow->m_pWorkspace->m_iID; 127 | pNode->workspaceName = pActiveWorkspace->m_szName; 128 | pNode->pWindow->m_iMonitorID = pTargetMonitor->ID; 129 | } 130 | 131 | // clean fullscreen status 132 | if (pWindow->m_bIsFullscreen) { 133 | pWindow->m_bIsFullscreen = false; 134 | } 135 | 136 | //clean floating status(only apply to old layout window) 137 | if (pWindow->m_bIsFloating && pNode->isInOldLayout) { 138 | pWindow->m_bIsFloating = false; 139 | pWindow->updateDynamicRules(); 140 | } 141 | 142 | recalculateMonitor(pWindow->m_iMonitorID); 143 | } 144 | 145 | 146 | void OvGridLayout::removeOldLayoutData(PHLWINDOW pWindow) { 147 | 148 | std::string *configLayoutName = &g_hycov_configLayoutName; 149 | switchToLayoutWithoutReleaseData(*configLayoutName); 150 | hycov_log(LOG,"remove data of old layout:{}",*configLayoutName); 151 | 152 | if(*configLayoutName == "dwindle") { 153 | // disable render client of old layout 154 | g_hycov_pHyprDwindleLayout_recalculateMonitorHook->hook(); 155 | g_hycov_pHyprDwindleLayout_recalculateWindowHook->hook(); 156 | g_hycov_pSDwindleNodeData_recalcSizePosRecursiveHook->hook(); 157 | 158 | // only remove data,not render anything,becaust still in overview 159 | g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); 160 | 161 | g_hycov_pSDwindleNodeData_recalcSizePosRecursiveHook->unhook(); 162 | g_hycov_pHyprDwindleLayout_recalculateWindowHook->unhook(); 163 | g_hycov_pHyprDwindleLayout_recalculateMonitorHook->unhook(); 164 | } else if(*configLayoutName == "master") { 165 | g_hycov_pHyprMasterLayout_recalculateMonitorHook->hook(); 166 | 167 | g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); 168 | 169 | g_hycov_pHyprMasterLayout_recalculateMonitorHook->unhook(); 170 | } else { 171 | // may be not support other layout 172 | hycov_log(ERR,"unknow old layout:{}",*configLayoutName); 173 | g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); 174 | } 175 | 176 | switchToLayoutWithoutReleaseData("ovgrid"); 177 | } 178 | 179 | void OvGridLayout::onWindowRemoved(PHLWINDOW pWindow) { 180 | const auto pNode = getNodeFromWindow(pWindow); 181 | 182 | if (!pNode) 183 | return; 184 | 185 | if(pNode->isInOldLayout) { // if client is taken from the old layout 186 | removeOldLayoutData(pWindow); 187 | } 188 | 189 | if (pWindow->m_bIsFullscreen) 190 | g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); 191 | 192 | if (!pWindow->m_sGroupData.pNextWindow.expired()) { 193 | if (pWindow->m_sGroupData.pNextWindow.lock() == pWindow) 194 | pWindow->m_sGroupData.pNextWindow.reset(); 195 | else { 196 | // find last window and update 197 | PHLWINDOW PWINDOWPREV = pWindow->getGroupPrevious(); 198 | const auto WINDOWISVISIBLE = pWindow->getGroupCurrent() == pWindow; 199 | 200 | if (WINDOWISVISIBLE) 201 | PWINDOWPREV->setGroupCurrent(pWindow->m_sGroupData.head ? pWindow->m_sGroupData.pNextWindow.lock() : PWINDOWPREV); 202 | 203 | PWINDOWPREV->m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow; 204 | 205 | pWindow->m_sGroupData.pNextWindow.reset(); 206 | 207 | if (pWindow->m_sGroupData.head) { 208 | std::swap(PWINDOWPREV->m_sGroupData.pNextWindow.lock()->m_sGroupData.head, pWindow->m_sGroupData.head); 209 | std::swap(PWINDOWPREV->m_sGroupData.pNextWindow.lock()->m_sGroupData.locked, pWindow->m_sGroupData.locked); 210 | } 211 | 212 | if (pWindow == m_pLastTiledWindow.lock()) 213 | m_pLastTiledWindow.reset(); 214 | 215 | pWindow->setHidden(false); 216 | 217 | pWindow->updateWindowDecos(); 218 | PWINDOWPREV->getGroupCurrent()->updateWindowDecos(); 219 | g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); 220 | 221 | // change node bind window in group 222 | pNode->pWindow = PWINDOWPREV->getGroupCurrent(); 223 | pNode->pWindow->m_pWorkspace = g_pCompositor->m_pLastMonitor->activeWorkspace; 224 | applyNodeDataToWindow(pNode); 225 | pNode->isInOldLayout = false; 226 | hycov_log(LOG,"change node bind window in group,old:{} new:{}",pWindow,pNode->pWindow); 227 | 228 | return; 229 | } 230 | } 231 | 232 | if (pWindow->m_bIsFloating) { 233 | onWindowRemovedFloating(pWindow); 234 | } else { 235 | onWindowRemovedTiling(pWindow); 236 | } 237 | 238 | if (pWindow == m_pLastTiledWindow.lock()) 239 | m_pLastTiledWindow.reset(); 240 | } 241 | 242 | void OvGridLayout::onWindowRemovedTiling(PHLWINDOW pWindow) 243 | { 244 | hycov_log(LOG,"remove tiling windwo:{}",pWindow); 245 | 246 | const auto pNode = getNodeFromWindow(pWindow); 247 | 248 | if (!pNode) 249 | return; 250 | 251 | if(pNode->isInOldLayout) { // if client is taken from the old layout 252 | removeOldLayoutData(pWindow); 253 | } 254 | 255 | // if window is in a group,replace it with other window in same group 256 | // pNode->pWindow->m_pWorkspace = g_pCompositor->getWorkspaceByID(pNode->workspaceID); 257 | // applyNodeDataToWindow(pNode); 258 | // pNode->isInOldLayout = false; 259 | // g_pCompositor->focusWindow(pNode->pWindow); 260 | // return; 261 | // } 262 | 263 | m_lOvGridNodesData.remove(*pNode); 264 | 265 | if(m_lOvGridNodesData.empty()){ 266 | return; 267 | } 268 | 269 | recalculateMonitor(pWindow->m_iMonitorID); 270 | 271 | } 272 | 273 | bool OvGridLayout::isWindowTiled(PHLWINDOW pWindow) 274 | { 275 | return getNodeFromWindow(pWindow) != nullptr; 276 | } 277 | 278 | void OvGridLayout::calculateWorkspace(const int &ws) 279 | { 280 | const auto pWorksapce = g_pCompositor->getWorkspaceByID(ws); 281 | auto dataSize = m_lOvGridNodesData.size(); 282 | auto pTempNodes = new SOvGridNodeData*[dataSize + 1]; 283 | SOvGridNodeData *pNode; 284 | int i, n = 0; 285 | int cx, cy; 286 | int dx, cw, ch;; 287 | int cols, rows, overcols,NODECOUNT; 288 | 289 | if (!pWorksapce) { 290 | delete[] pTempNodes; 291 | return; 292 | } 293 | 294 | NODECOUNT = getNodesNumOnWorkspace(pWorksapce->m_iID); 295 | const auto pMonitor = g_pCompositor->getMonitorFromID(pWorksapce->m_iMonitorID); 296 | 297 | if (NODECOUNT == 0) { 298 | delete[] pTempNodes; 299 | return; 300 | } 301 | 302 | static const auto *PBORDERSIZE = &g_hycov_bordersize; 303 | static const auto *GAPPO = &g_hycov_overview_gappo; 304 | static const auto *GAPPI = &g_hycov_overview_gappi; 305 | 306 | /* 307 | m is region that is moniotr, 308 | w is region that is monitor but don not contain bar 309 | */ 310 | int m_x = pMonitor->vecPosition.x; 311 | int m_y = pMonitor->vecPosition.y; 312 | int w_x = pMonitor->vecPosition.x + pMonitor->vecReservedTopLeft.x; 313 | int w_y = pMonitor->vecPosition.y + pMonitor->vecReservedTopLeft.y; 314 | int m_width = pMonitor->vecSize.x; 315 | int m_height = pMonitor->vecSize.y; 316 | int w_width = pMonitor->vecSize.x - pMonitor->vecReservedTopLeft.x; 317 | int w_height = pMonitor->vecSize.y - pMonitor->vecReservedTopLeft.y; 318 | 319 | for (auto &node : m_lOvGridNodesData) 320 | { 321 | if (node.workspaceID == ws) 322 | { 323 | pTempNodes[n] = &node; 324 | n++; 325 | } 326 | } 327 | 328 | pTempNodes[n] = NULL; 329 | 330 | if (NODECOUNT == 0) { 331 | delete[] pTempNodes; 332 | return; 333 | } 334 | 335 | // one client arrange 336 | if (NODECOUNT == 1) 337 | { 338 | pNode = pTempNodes[0]; 339 | cw = (w_width - 2 * (*GAPPO)) * 0.7; 340 | ch = (w_height - 2 * (*GAPPO)) * 0.8; 341 | resizeNodeSizePos(pNode, w_x + (int)((m_width - cw) / 2), w_y + (int)((w_height - ch) / 2), 342 | cw - 2 * (*PBORDERSIZE), ch - 2 * (*PBORDERSIZE)); 343 | delete[] pTempNodes; 344 | return; 345 | } 346 | 347 | // two client arrange 348 | if (NODECOUNT == 2) 349 | { 350 | pNode = pTempNodes[0]; 351 | cw = (w_width - 2 * (*GAPPO) - (*GAPPI)) / 2; 352 | ch = (w_height - 2 * (*GAPPO)) * 0.65; 353 | resizeNodeSizePos(pNode, m_x + cw + (*GAPPO) + (*GAPPI), m_y + (m_height - ch) / 2 + (*GAPPO), 354 | cw - 2 * (*PBORDERSIZE), ch - 2 * (*PBORDERSIZE)); 355 | resizeNodeSizePos(pTempNodes[1], m_x + (*GAPPO), m_y + (m_height - ch) / 2 + (*GAPPO), 356 | cw - 2 * (*PBORDERSIZE), ch - 2 * (*PBORDERSIZE)); 357 | delete[] pTempNodes; 358 | return; 359 | } 360 | 361 | //more than two client arrange 362 | 363 | //Calculate the integer part of the square root of the number of nodes 364 | for (cols = 0; cols <= NODECOUNT / 2; cols++) 365 | if (cols * cols >= NODECOUNT) 366 | break; 367 | 368 | //The number of rows and columns multiplied by the number of nodes 369 | // must be greater than the number of nodes to fit all the Windows 370 | rows = (cols && (cols - 1) * cols >= NODECOUNT) ? cols - 1 : cols; 371 | 372 | //Calculate the width and height of the layout area based on 373 | //the number of rows and columns 374 | ch = (int)((w_height - 2 * (*GAPPO) - (rows - 1) * (*GAPPI)) / rows); 375 | cw = (int)((w_width - 2 * (*GAPPO) - (cols - 1) * (*GAPPI)) / cols); 376 | 377 | //If the nodes do not exactly fill all rows, 378 | //the number of Windows in the unfilled rows is 379 | overcols = NODECOUNT % cols; 380 | 381 | if (overcols) 382 | dx = (int)((w_width - overcols * cw - (overcols - 1) * (*GAPPI)) / 2) - (*GAPPO); 383 | for (i = 0, pNode = pTempNodes[0]; pNode; pNode = pTempNodes[i + 1], i++) 384 | { 385 | cx = w_x + (i % cols) * (cw + (*GAPPI)); 386 | cy = w_y + (int)(i / cols) * (ch + (*GAPPI)); 387 | if (overcols && i >= (NODECOUNT-overcols)) 388 | { 389 | cx += dx; 390 | } 391 | resizeNodeSizePos(pNode, cx + (*GAPPO), cy + (*GAPPO), cw - 2 * (*PBORDERSIZE), ch - 2 * (*PBORDERSIZE)); 392 | } 393 | delete[] pTempNodes; 394 | } 395 | 396 | void OvGridLayout::recalculateMonitor(const int &monid) 397 | { 398 | const auto pMonitor = g_pCompositor->getMonitorFromID(monid); // 根据monitor id获取monitor对象 399 | 400 | if(!pMonitor || !pMonitor->activeWorkspace) 401 | return; 402 | 403 | g_pHyprRenderer->damageMonitor(pMonitor); // Use local rendering 404 | 405 | if (pMonitor->activeSpecialWorkspaceID()) { 406 | calculateWorkspace(pMonitor->activeSpecialWorkspaceID()); 407 | return; 408 | } 409 | 410 | const auto pWorksapce = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspaceID()); // 获取当前workspace对象 411 | if (!pWorksapce) 412 | return; 413 | 414 | calculateWorkspace(pWorksapce->m_iID); // calculate windwo's size and position 415 | } 416 | 417 | // set window's size and position 418 | void OvGridLayout::applyNodeDataToWindow(SOvGridNodeData *pNode) 419 | { 420 | 421 | const auto pWindow = pNode->pWindow; 422 | 423 | // force disable decorate and shadow 424 | // pWindow->m_sSpecialRenderData.decorate = false; 425 | // pWindow->m_sSpecialRenderData.shadow = false; 426 | 427 | // force enable bordear and rounding 428 | pWindow->m_sSpecialRenderData.border = true; 429 | pWindow->m_sSpecialRenderData.rounding = true; 430 | 431 | pWindow->m_vSize = pNode->size; 432 | pWindow->m_vPosition = pNode->position; 433 | 434 | auto calcPos = pWindow->m_vPosition; 435 | auto calcSize = pWindow->m_vSize; 436 | 437 | pWindow->m_vRealSize = calcSize; 438 | pWindow->m_vRealPosition = calcPos; 439 | g_pXWaylandManager->setWindowSize(pWindow, calcSize); 440 | 441 | pWindow->updateWindowDecos(); 442 | } 443 | 444 | void OvGridLayout::recalculateWindow(PHLWINDOW pWindow) 445 | { 446 | ; // empty 447 | } 448 | 449 | 450 | void OvGridLayout::resizeActiveWindow(const Vector2D &pixResize, eRectCorner corner, PHLWINDOW pWindow) 451 | { 452 | ; // empty 453 | } 454 | 455 | void OvGridLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscreenMode mode, bool on) 456 | { 457 | ; // empty 458 | } 459 | 460 | std::any OvGridLayout::layoutMessage(SLayoutMessageHeader header, std::string content) 461 | { 462 | return ""; 463 | } 464 | 465 | SWindowRenderLayoutHints OvGridLayout::requestRenderHints(PHLWINDOW pWindow) 466 | { 467 | return {}; 468 | } 469 | 470 | void OvGridLayout::switchWindows(PHLWINDOW pWindowA, PHLWINDOW pWindowB) 471 | { 472 | ; // empty 473 | } 474 | 475 | void OvGridLayout::alterSplitRatio(PHLWINDOW pWindow, float delta, bool exact) 476 | { 477 | ; // empty 478 | } 479 | 480 | std::string OvGridLayout::getLayoutName() 481 | { 482 | return "ovgrid"; 483 | } 484 | 485 | void OvGridLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) 486 | { 487 | ; // empty 488 | } 489 | 490 | void OvGridLayout::moveWindowTo(PHLWINDOW , const std::string &dir, bool silent) 491 | { 492 | ; // empty 493 | } 494 | 495 | void OvGridLayout::changeToActivceSourceWorkspace() 496 | { 497 | PHLWINDOW pWindow = nullptr; 498 | SOvGridNodeData *pNode; 499 | PHLWORKSPACE pWorksapce; 500 | hycov_log(LOG,"changeToActivceSourceWorkspace"); 501 | pWindow = g_pCompositor->m_pLastWindow.lock(); 502 | pNode = getNodeFromWindow(pWindow); 503 | if(pNode) { 504 | pWorksapce = g_pCompositor->getWorkspaceByID(pNode->ovbk_windowWorkspaceId); 505 | } else if(pWindow) { 506 | pWorksapce = pWindow->m_pWorkspace; 507 | } else { 508 | pWorksapce = g_pCompositor->m_pLastMonitor->activeWorkspace; 509 | } 510 | // pMonitor->changeWorkspace(pWorksapce); 511 | hycov_log(LOG,"changeToWorkspace:{}",pWorksapce->m_iID); 512 | g_pEventManager->postEvent(SHyprIPCEvent{"workspace", pWorksapce->m_szName}); 513 | EMIT_HOOK_EVENT("workspace", pWorksapce); 514 | } 515 | 516 | void OvGridLayout::moveWindowToSourceWorkspace() 517 | { 518 | PHLWORKSPACE pWorkspace; 519 | 520 | hycov_log(LOG,"moveWindowToSourceWorkspace"); 521 | 522 | for (auto &nd : m_lOvGridNodesData) 523 | { 524 | if (nd.pWindow && (nd.pWindow->m_pWorkspace->m_iID != nd.ovbk_windowWorkspaceId || nd.workspaceName != nd.ovbk_windowWorkspaceName )) 525 | { 526 | pWorkspace = g_pCompositor->getWorkspaceByID(nd.ovbk_windowWorkspaceId); 527 | if (!pWorkspace){ 528 | hycov_log(LOG,"source workspace no exist"); 529 | g_hycov_pSpawnHook->hook(); // disable on-emptty-create workspace rule 530 | pWorkspace = g_pCompositor->createNewWorkspace(nd.ovbk_windowWorkspaceId,nd.ovbk_windowMonitorId,nd.ovbk_windowWorkspaceName); 531 | g_hycov_pSpawnHook->unhook(); 532 | hycov_log(LOG,"create workspace: id:{} monitor:{} name:{}",nd.ovbk_windowWorkspaceId,nd.pWindow->m_iMonitorID,nd.ovbk_windowWorkspaceName); 533 | } 534 | nd.pWindow->m_iMonitorID = nd.ovbk_windowMonitorId; 535 | nd.pWindow->m_pWorkspace = pWorkspace; 536 | nd.workspaceID = nd.ovbk_windowWorkspaceId; 537 | nd.workspaceName = nd.ovbk_windowWorkspaceName; 538 | nd.pWindow->m_vPosition = nd.ovbk_position; 539 | nd.pWindow->m_vSize = nd.ovbk_size; 540 | g_pHyprRenderer->damageWindow(nd.pWindow); 541 | } 542 | } 543 | } 544 | 545 | // it will exec once when change layout enable 546 | void OvGridLayout::onEnable() 547 | { 548 | 549 | for (auto &w : g_pCompositor->m_vWindows) 550 | { 551 | PHLWINDOW pWindow = w; 552 | 553 | if (pWindow->isHidden() || !pWindow->m_bIsMapped || pWindow->m_bFadingOut) 554 | continue; 555 | 556 | if(pWindow->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && g_hycov_only_active_monitor && !g_hycov_forece_display_all && !g_hycov_forece_display_all_in_one_monitor) 557 | continue; 558 | 559 | const auto pNode = &m_lSOldLayoutRecordNodeData.emplace_back(); 560 | pNode->pWindow = pWindow; 561 | onWindowCreatedTiling(pWindow); 562 | } 563 | } 564 | 565 | // it will exec once when change layout disable 566 | void OvGridLayout::onDisable() 567 | { 568 | dispatch_leaveoverview(""); 569 | } 570 | -------------------------------------------------------------------------------- /src/OvGridLayout.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | struct SOvGridNodeData 7 | { 8 | PHLWINDOW pWindow = nullptr; 9 | int ovbk_windowWorkspaceId = -1; 10 | std::string ovbk_windowWorkspaceName; 11 | int ovbk_windowMonitorId = -1; 12 | std::string workspaceName; 13 | bool ovbk_windowIsFloating = false; 14 | bool ovbk_windowIsFullscreen = false; 15 | eFullscreenMode ovbk_windowFullscreenMode ; 16 | Vector2D ovbk_position; 17 | Vector2D ovbk_size; 18 | Vector2D position; 19 | Vector2D size; 20 | bool ovbk_windowIsWithBorder; 21 | bool ovbk_windowIsWithDecorate; 22 | bool ovbk_windowIsWithRounding; 23 | bool ovbk_windowIsWithShadow; 24 | bool isInOldLayout = false; 25 | bool isGroupActive = false; 26 | 27 | int workspaceID = -1; 28 | 29 | bool operator==(const SOvGridNodeData &rhs) const 30 | { 31 | return pWindow == rhs.pWindow; 32 | } 33 | }; 34 | 35 | 36 | struct SOldLayoutRecordNodeData 37 | { 38 | PHLWINDOW pWindow = nullptr; 39 | bool operator==(const SOldLayoutRecordNodeData &rhs) const 40 | { 41 | return pWindow == rhs.pWindow; 42 | } 43 | }; 44 | 45 | 46 | class OvGridLayout : public IHyprLayout 47 | { 48 | public: 49 | virtual void onWindowCreatedTiling(PHLWINDOW , eDirection direction = DIRECTION_DEFAULT); 50 | virtual void onWindowRemovedTiling(PHLWINDOW ); 51 | virtual void onWindowRemoved(PHLWINDOW ); 52 | virtual bool isWindowTiled(PHLWINDOW ); 53 | virtual PHLWINDOW getNextWindowCandidate(PHLWINDOW); 54 | virtual void recalculateMonitor(const int &); 55 | virtual void recalculateWindow(PHLWINDOW ); 56 | virtual void resizeActiveWindow(const Vector2D &, eRectCorner corner, PHLWINDOW pWindow = nullptr); 57 | virtual void fullscreenRequestForWindow(PHLWINDOW , eFullscreenMode, bool); 58 | virtual std::any layoutMessage(SLayoutMessageHeader, std::string); 59 | virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW ); 60 | virtual void switchWindows(PHLWINDOW , PHLWINDOW ); 61 | virtual void alterSplitRatio(PHLWINDOW , float, bool); 62 | virtual std::string getLayoutName(); 63 | virtual Vector2D predictSizeForNewWindowTiled(); 64 | virtual void replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to); 65 | virtual void moveWindowTo(PHLWINDOW, const std::string& direction, bool silent = false); 66 | virtual void onEnable(); 67 | virtual void onDisable(); 68 | void applyNodeDataToWindow(SOvGridNodeData *); 69 | void calculateWorkspace(const int &); 70 | int getNodesNumOnWorkspace(const int &); 71 | SOvGridNodeData *getNodeFromWindow(PHLWINDOW ); 72 | SOldLayoutRecordNodeData *getOldLayoutRecordNodeFromWindow(PHLWINDOW ); 73 | void resizeNodeSizePos(SOvGridNodeData *, int, int, int, int); 74 | void moveWindowToWorkspaceSilent(PHLWINDOW , const int &); 75 | std::list m_lOvGridNodesData; 76 | std::list m_lSOldLayoutRecordNodeData; 77 | void moveWindowToSourceWorkspace(); 78 | void changeToActivceSourceWorkspace(); 79 | void removeOldLayoutData(PHLWINDOW pWindow); 80 | private: 81 | }; -------------------------------------------------------------------------------- /src/dispatchers.cpp: -------------------------------------------------------------------------------- 1 | #include "dispatchers.hpp" 2 | 3 | static const std::string overviewWorksapceName = "OVERVIEW"; 4 | static std::string workspaceNameBackup; 5 | static int workspaceIdBackup; 6 | 7 | void recalculateAllMonitor() { 8 | for (auto &m : g_pCompositor->m_vMonitors) { 9 | CMonitor *pMonitor = m.get(); 10 | g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID); 11 | } 12 | } 13 | 14 | // only change layout,keep data of previous layout 15 | void switchToLayoutWithoutReleaseData(std::string layout) { 16 | for (size_t i = 0; i < g_pLayoutManager->m_vLayouts.size(); ++i) { 17 | if (g_pLayoutManager->m_vLayouts[i].first == layout) { 18 | if (i == (size_t)g_pLayoutManager->m_iCurrentLayoutID) 19 | return; 20 | g_pLayoutManager->m_iCurrentLayoutID = i; 21 | return; 22 | } 23 | } 24 | hycov_log(ERR, "Unknown layout!"); 25 | } 26 | 27 | bool want_auto_fullscren(PHLWINDOW pWindow) { 28 | int nodeNumInTargetWorkspace = 1; 29 | 30 | if(!pWindow) { 31 | return false; 32 | } 33 | 34 | auto pNode = g_hycov_OvGridLayout->getNodeFromWindow(pWindow); 35 | 36 | if(!pNode) { 37 | return true; 38 | } 39 | 40 | // if client is fullscreen before,don't make it fullscreen 41 | if (pNode->ovbk_windowIsFullscreen) { 42 | return false; 43 | } 44 | 45 | // caculate the number of clients that will be in the same workspace with pWindow(don't contain itself) 46 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) { 47 | if(n.pWindow != pNode->pWindow && n.ovbk_windowWorkspaceId == pNode->ovbk_windowWorkspaceId) { 48 | nodeNumInTargetWorkspace++; 49 | } 50 | } 51 | 52 | // if only one client in workspace(pWindow itself), don't make it fullscreen 53 | if(nodeNumInTargetWorkspace > 1) { 54 | return true; 55 | } else { 56 | return false; 57 | } 58 | } 59 | 60 | bool isDirectionArg(std::string arg) { 61 | if (arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "left" || arg == "right" || arg == "up" || arg == "down" || arg == "leftcross" || arg == "rightcross" || arg == "upcross" || arg == "downcross") { 62 | return true; 63 | } else { 64 | return false; 65 | } 66 | } 67 | 68 | bool isCrossMonitor(std::string arg) { 69 | if (arg == "leftcross" || arg == "rightcross" || arg == "upcross" || arg == "downcross") { 70 | return true; 71 | } else { 72 | return false; 73 | } 74 | } 75 | 76 | std::optional parseShiftArg(std::string arg) { 77 | if (arg == "l" || arg == "left" || arg == "leftcross") return ShiftDirection::Left; 78 | else if (arg == "r" || arg == "right" || arg == "rightcross") return ShiftDirection::Right; 79 | else if (arg == "u" || arg == "up" || arg == "upcross") return ShiftDirection::Up; 80 | else if (arg == "d" || arg == "down" || arg == "downcross") return ShiftDirection::Down; 81 | else return {}; 82 | } 83 | 84 | PHLWINDOW direction_select(std::string arg){ 85 | PHLWINDOW pTempClient = g_pCompositor->m_pLastWindow.lock(); 86 | auto dataSize = g_pCompositor->m_vWindows.size(); 87 | auto pTempCWindows = new PHLWINDOW[dataSize + 1]; 88 | PHLWINDOW pTempFocusCWindows = nullptr; 89 | int last = -1; 90 | if(!pTempClient){ 91 | delete[] pTempCWindows; 92 | return nullptr; 93 | }else if (pTempClient->m_bIsFullscreen){ 94 | delete[] pTempCWindows; 95 | return nullptr; 96 | } 97 | 98 | if (!isDirectionArg(arg)) { 99 | hycov_log(ERR, "Cannot move focus in direction {}, unsupported direction. Supported: l/left/leftcross,r/right/rightcross,u/up/upcross,d/down/downcross", arg); 100 | delete[] pTempCWindows; 101 | return nullptr; 102 | } 103 | 104 | for (auto &w : g_pCompositor->m_vWindows) 105 | { 106 | PHLWINDOW pWindow = w; 107 | 108 | if (pTempClient == pWindow || pWindow->isHidden() || !pWindow->m_bIsMapped || pWindow->m_bFadingOut || pWindow->m_bIsFullscreen) { 109 | continue; 110 | } 111 | 112 | auto *pMonitor = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); 113 | 114 | if (!((isCrossMonitor(arg) && pWindow->m_iMonitorID != pTempClient->m_iMonitorID && !pTempClient->m_pWorkspace->m_bIsSpecialWorkspace && pWindow->m_pWorkspace == pMonitor->activeWorkspace ) || pTempClient->m_pWorkspace == pWindow->m_pWorkspace)) { 115 | continue; 116 | } 117 | 118 | last++; 119 | pTempCWindows[last] = pWindow; 120 | } 121 | 122 | if (last < 0) { 123 | delete[] pTempCWindows; 124 | return nullptr; 125 | } 126 | int sel_x = pTempClient->m_vRealPosition.goal().x; 127 | int sel_y = pTempClient->m_vRealPosition.goal().y; 128 | long long int distance = LLONG_MAX;; 129 | // int temp_focus = 0; 130 | 131 | auto values = CVarList(arg); 132 | auto shift = parseShiftArg(values[0]); 133 | switch (shift.value()) { 134 | case ShiftDirection::Up: 135 | // Find the window with the closest coordinates 136 | // in the top left corner of the window (is limited to same x) 137 | for (int _i = 0; _i <= last; _i++) { 138 | if (pTempCWindows[_i]->m_vRealPosition.goal().y < sel_y && pTempCWindows[_i]->m_vRealPosition.goal().x == sel_x) { 139 | int dis_x = pTempCWindows[_i]->m_vRealPosition.goal().x - sel_x; 140 | int dis_y = pTempCWindows[_i]->m_vRealPosition.goal().y - sel_y; 141 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 142 | if (tmp_distance < distance) { 143 | distance = tmp_distance; 144 | pTempFocusCWindows = pTempCWindows[_i]; 145 | } 146 | } 147 | } 148 | // if find nothing above 149 | // find again(is unlimited to x) 150 | if(!pTempFocusCWindows){ 151 | for (int _i = 0; _i <= last; _i++) { 152 | if (pTempCWindows[_i]->m_vRealPosition.goal().y < sel_y ) { 153 | int dis_x = pTempCWindows[_i]->m_vRealPosition.goal().x - sel_x; 154 | int dis_y = pTempCWindows[_i]->m_vRealPosition.goal().y - sel_y; 155 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 156 | if (tmp_distance < distance) { 157 | distance = tmp_distance; 158 | pTempFocusCWindows = pTempCWindows[_i]; 159 | } 160 | } 161 | } 162 | } 163 | break; 164 | case ShiftDirection::Down: 165 | for (int _i = 0; _i <= last; _i++) { 166 | if (pTempCWindows[_i]->m_vRealPosition.goal().y > sel_y && pTempCWindows[_i]->m_vRealPosition.goal().x == sel_x) { 167 | int dis_x = pTempCWindows[_i]->m_vRealPosition.goal().x - sel_x; 168 | int dis_y = pTempCWindows[_i]->m_vRealPosition.goal().y - sel_y; 169 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 170 | if (tmp_distance < distance) { 171 | distance = tmp_distance; 172 | pTempFocusCWindows = pTempCWindows[_i]; 173 | } 174 | } 175 | } 176 | if(!pTempFocusCWindows){ 177 | for (int _i = 0; _i <= last; _i++) { 178 | if (pTempCWindows[_i]->m_vRealPosition.goal().y > sel_y ) { 179 | int dis_x = pTempCWindows[_i]->m_vRealPosition.goal().x - sel_x; 180 | int dis_y = pTempCWindows[_i]->m_vRealPosition.goal().y - sel_y; 181 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 182 | if (tmp_distance < distance) { 183 | distance = tmp_distance; 184 | pTempFocusCWindows = pTempCWindows[_i]; 185 | } 186 | } 187 | } 188 | } 189 | break; 190 | case ShiftDirection::Left: 191 | for (int _i = 0; _i <= last; _i++) { 192 | if (pTempCWindows[_i]->m_vRealPosition.goal().x < sel_x && pTempCWindows[_i]->m_vRealPosition.goal().y == sel_y) { 193 | int dis_x = pTempCWindows[_i]->m_vRealPosition.goal().x - sel_x; 194 | int dis_y = pTempCWindows[_i]->m_vRealPosition.goal().y - sel_y; 195 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 196 | if (tmp_distance < distance) { 197 | distance = tmp_distance; 198 | pTempFocusCWindows = pTempCWindows[_i]; 199 | } 200 | } 201 | } 202 | if(!pTempFocusCWindows){ 203 | for (int _i = 0; _i <= last; _i++) { 204 | if (pTempCWindows[_i]->m_vRealPosition.goal().x < sel_x) { 205 | int dis_x = pTempCWindows[_i]->m_vRealPosition.goal().x - sel_x; 206 | int dis_y = pTempCWindows[_i]->m_vRealPosition.goal().y - sel_y; 207 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 208 | if (tmp_distance < distance) { 209 | distance = tmp_distance; 210 | pTempFocusCWindows = pTempCWindows[_i]; 211 | } 212 | } 213 | } 214 | } 215 | break; 216 | case ShiftDirection::Right: 217 | for (int _i = 0; _i <= last; _i++) { 218 | if (pTempCWindows[_i]->m_vRealPosition.goal().x > sel_x && pTempCWindows[_i]->m_vRealPosition.goal().y == sel_y) { 219 | int dis_x = pTempCWindows[_i]->m_vRealPosition.goal().x - sel_x; 220 | int dis_y = pTempCWindows[_i]->m_vRealPosition.goal().y - sel_y; 221 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 222 | if (tmp_distance < distance) { 223 | distance = tmp_distance; 224 | pTempFocusCWindows = pTempCWindows[_i]; 225 | } 226 | } 227 | } 228 | if(!pTempFocusCWindows){ 229 | for (int _i = 0; _i <= last; _i++) { 230 | if (pTempCWindows[_i]->m_vRealPosition.goal().x > sel_x) { 231 | int dis_x = pTempCWindows[_i]->m_vRealPosition.goal().x - sel_x; 232 | int dis_y = pTempCWindows[_i]->m_vRealPosition.goal().y - sel_y; 233 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 234 | if (tmp_distance < distance) { 235 | distance = tmp_distance; 236 | pTempFocusCWindows = pTempCWindows[_i]; 237 | } 238 | } 239 | } 240 | } 241 | break; 242 | } 243 | delete[] pTempCWindows; 244 | return pTempFocusCWindows; 245 | } 246 | 247 | PHLWINDOW get_circle_next_window (std::string arg) { 248 | bool next_ready = false; 249 | PHLWINDOW pTempClient = g_pCompositor->m_pLastWindow.lock(); 250 | 251 | if(!pTempClient) 252 | return nullptr; 253 | 254 | for (auto &w : g_pCompositor->m_vWindows) 255 | { 256 | PHLWINDOW pWindow = w; 257 | if (pTempClient->m_pWorkspace != pWindow->m_pWorkspace || pWindow->isHidden() || !pWindow->m_bIsMapped || pWindow->m_bFadingOut || pWindow->m_bIsFullscreen) 258 | continue; 259 | if (next_ready) 260 | return pWindow; 261 | if (pWindow == pTempClient) 262 | next_ready = true; 263 | } 264 | 265 | for (auto &w : g_pCompositor->m_vWindows) 266 | { 267 | PHLWINDOW pWindow = w; 268 | if (pTempClient->m_pWorkspace != pWindow->m_pWorkspace || pWindow->isHidden() || !pWindow->m_bIsMapped || pWindow->m_bFadingOut || pWindow->m_bIsFullscreen) 269 | continue; 270 | return pWindow; 271 | } 272 | return nullptr; 273 | } 274 | 275 | void warpcursor_and_focus_to_window(PHLWINDOW pWindow) { 276 | g_pCompositor->focusWindow(pWindow); 277 | g_pCompositor->warpCursorTo(pWindow->middle()); 278 | } 279 | 280 | void dispatch_circle(std::string arg) 281 | { 282 | PHLWINDOW pWindow; 283 | pWindow = get_circle_next_window(arg); 284 | if(pWindow){ 285 | warpcursor_and_focus_to_window(pWindow); 286 | } 287 | } 288 | 289 | void dispatch_focusdir(std::string arg) 290 | { 291 | PHLWINDOW pWindow; 292 | pWindow = direction_select(arg); 293 | if(pWindow){ 294 | warpcursor_and_focus_to_window(pWindow); 295 | } 296 | } 297 | 298 | void dispatch_toggleoverview(std::string arg) 299 | { 300 | if (g_hycov_isOverView && (!g_hycov_enable_alt_release_exit || arg == "internalToggle")) { 301 | dispatch_leaveoverview(""); 302 | hycov_log(LOG,"leave overview:toggleMethod:{},enable_alt_release_exit:{}",arg,g_hycov_enable_alt_release_exit); 303 | } else if (g_hycov_isOverView && g_hycov_enable_alt_release_exit && arg != "internalToggle") { 304 | dispatch_circle(""); 305 | hycov_log(LOG,"toggle overview:switch focus circlely"); 306 | } else if(g_hycov_enable_alt_release_exit && g_hycov_alt_toggle_auto_next && arg != "internalToggle") { 307 | dispatch_enteroverview(arg); 308 | dispatch_circle(""); 309 | hycov_log(LOG,"enter overview:alt switch mode auto next"); 310 | } else { 311 | dispatch_enteroverview(arg); 312 | hycov_log(LOG,"enter overview:toggleMethod:{}",arg); 313 | } 314 | } 315 | 316 | void dispatch_enteroverview(std::string arg) 317 | { 318 | if(g_hycov_isOverView) { 319 | return; 320 | } 321 | 322 | const auto pMonitor = g_pCompositor->m_pLastMonitor; 323 | if(pMonitor->activeSpecialWorkspaceID() != 0) 324 | pMonitor->setSpecialWorkspace(nullptr); 325 | 326 | //force display all workspace window,ignore `only_active_worksapce` and `only_active_monitor` 327 | if (arg == "forceall") { 328 | g_hycov_forece_display_all = true; 329 | hycov_log(LOG,"force display all clients"); 330 | } else { 331 | g_hycov_forece_display_all = false; 332 | } 333 | 334 | //force display all workspace window in one monitor,ignore `only_active_worksapce` and `only_active_monitor` 335 | if (arg == "forceallinone") { 336 | g_hycov_forece_display_all_in_one_monitor = true; 337 | hycov_log(LOG,"force display all clients in one monitor"); 338 | } else { 339 | g_hycov_forece_display_all_in_one_monitor = false; 340 | } 341 | 342 | //force only display current workspace,ignore `only_active_worksapce` and `only_active_monitor` 343 | if (arg == "onlycurrentworkspace") { 344 | g_hycov_force_display_only_current_workspace = true; 345 | hycov_log(LOG,"force display only current workspace"); 346 | } else { 347 | g_hycov_force_display_only_current_workspace = false; 348 | } 349 | 350 | //ali clients exit fullscreen status before enter overview 351 | PHLWINDOW pFullscreenWindow; 352 | PHLWINDOW pActiveWindow = g_pCompositor->m_pLastWindow.lock(); 353 | PHLWORKSPACE pActiveWorkspace; 354 | CMonitor *pActiveMonitor; 355 | 356 | bool isNoShouldTileWindow = true; 357 | 358 | for (auto &w : g_pCompositor->m_vWindows) 359 | { 360 | PHLWINDOW pWindow = w; 361 | if (pWindow->isHidden() || !pWindow->m_bIsMapped || pWindow->m_bFadingOut || pWindow->m_pWorkspace->m_bIsSpecialWorkspace) 362 | continue; 363 | isNoShouldTileWindow = false; 364 | } 365 | 366 | //if no clients, forbit enter overview 367 | if(isNoShouldTileWindow){ 368 | return; 369 | } 370 | 371 | hycov_log(LOG,"enter overview"); 372 | g_hycov_isOverView = true; 373 | 374 | //make all fullscreen window exit fullscreen state 375 | for (auto &w : g_pCompositor->m_vWorkspaces) 376 | { 377 | CWorkspace *pWorkspace = w.get(); 378 | if (pWorkspace->m_bHasFullscreenWindow) 379 | { 380 | pFullscreenWindow = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID); 381 | g_pCompositor->setWindowFullscreen(pFullscreenWindow, false, FULLSCREEN_FULL); 382 | 383 | //let overview know the client is a fullscreen before 384 | pFullscreenWindow->m_bIsFullscreen = true; 385 | } 386 | } 387 | 388 | //enter overview layout 389 | // g_pLayoutManager->switchToLayout("ovgrid"); 390 | switchToLayoutWithoutReleaseData("ovgrid"); 391 | g_pLayoutManager->getCurrentLayout()->onEnable(); 392 | 393 | //change workspace name to OVERVIEW 394 | pActiveMonitor = g_pCompositor->m_pLastMonitor.get(); 395 | pActiveWorkspace = g_pCompositor->getWorkspaceByID(pActiveMonitor->activeWorkspace->m_iID); 396 | workspaceNameBackup = pActiveWorkspace->m_szName; 397 | workspaceIdBackup = pActiveWorkspace->m_iID; 398 | g_pCompositor->renameWorkspace(pActiveMonitor->activeWorkspace->m_iID,overviewWorksapceName); 399 | 400 | //Preserve window focus 401 | if(pActiveWindow){ 402 | g_pCompositor->focusWindow(pActiveWindow); //restore the focus to before active window 403 | 404 | } else { // when no window is showed in current window,find from other workspace to focus(exclude special workspace) 405 | for (auto &w : g_pCompositor->m_vWindows) { 406 | PHLWINDOW pWindow = w; 407 | auto node = g_hycov_OvGridLayout->getNodeFromWindow(pWindow); 408 | if ( !node || g_pCompositor->isWorkspaceSpecial(node->workspaceID) || pWindow->isHidden() || !pWindow->m_bIsMapped || pWindow->m_bFadingOut || pWindow->m_bIsFullscreen) 409 | continue; 410 | g_pCompositor->focusWindow(pWindow); // find the last window that is in same workspace with the remove window 411 | } 412 | 413 | } 414 | 415 | // enable hook fullscreenActive funciton 416 | g_hycov_pFullscreenActiveHook->hook(); 417 | 418 | //disable changeworkspace 419 | if(g_hycov_disable_workspace_change) { 420 | g_hycov_pChangeworkspaceHook->hook(); 421 | g_hycov_pMoveActiveToWorkspaceHook->hook(); 422 | } 423 | 424 | //disable spawn 425 | if(g_hycov_disable_spawn) { 426 | g_hycov_pSpawnHook->hook(); 427 | } 428 | 429 | g_hycov_pCKeybindManager_changeGroupActiveHook->hook(); 430 | g_hycov_pCKeybindManager_toggleGroupHook->hook(); 431 | g_hycov_pCKeybindManager_moveOutOfGroupHook->hook(); 432 | 433 | return; 434 | } 435 | 436 | void dispatch_leaveoverview(std::string arg) 437 | { 438 | if(!g_hycov_isOverView) { 439 | return; 440 | } 441 | 442 | const auto pMonitor = g_pCompositor->m_pLastMonitor; 443 | if(pMonitor->activeSpecialWorkspaceID() != 0) 444 | pMonitor->setSpecialWorkspace(nullptr); 445 | 446 | // get default layout 447 | std::string *configLayoutName = &g_hycov_configLayoutName; 448 | 449 | hycov_log(LOG,"leave overview"); 450 | g_hycov_isOverView = false; 451 | //mark exiting overview mode 452 | g_hycov_isOverViewExiting = true; 453 | 454 | //restore workspace name 455 | g_pCompositor->renameWorkspace(workspaceIdBackup,workspaceNameBackup); 456 | 457 | //enable changeworkspace 458 | if(g_hycov_disable_workspace_change) { 459 | g_hycov_pChangeworkspaceHook->unhook(); 460 | g_hycov_pMoveActiveToWorkspaceHook->unhook(); 461 | } 462 | 463 | //enable spawn 464 | if(g_hycov_disable_spawn) { 465 | g_hycov_pSpawnHook->unhook(); 466 | } 467 | 468 | g_hycov_pCKeybindManager_changeGroupActiveHook->unhook(); 469 | g_hycov_pCKeybindManager_toggleGroupHook->unhook(); 470 | g_hycov_pCKeybindManager_moveOutOfGroupHook->unhook(); 471 | 472 | // if no clients, just exit overview, don't restore client's state 473 | if (g_hycov_OvGridLayout->m_lOvGridNodesData.empty()) 474 | { 475 | switchToLayoutWithoutReleaseData(*configLayoutName); 476 | recalculateAllMonitor(); 477 | g_hycov_OvGridLayout->m_lOvGridNodesData.clear(); 478 | g_hycov_isOverViewExiting = false; 479 | return; 480 | } 481 | 482 | //move clients to it's original workspace 483 | g_hycov_OvGridLayout->moveWindowToSourceWorkspace(); 484 | // go to the workspace where the active client was before 485 | g_hycov_OvGridLayout->changeToActivceSourceWorkspace(); 486 | 487 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) 488 | { 489 | //make all window restore it's style 490 | n.pWindow->m_sSpecialRenderData.border = n.ovbk_windowIsWithBorder; 491 | n.pWindow->m_sSpecialRenderData.decorate = n.ovbk_windowIsWithDecorate; 492 | n.pWindow->m_sSpecialRenderData.rounding = n.ovbk_windowIsWithRounding; 493 | n.pWindow->m_sSpecialRenderData.shadow = n.ovbk_windowIsWithShadow; 494 | 495 | if (n.ovbk_windowIsFloating) 496 | { 497 | //make floating client restore it's floating status 498 | n.pWindow->m_bIsFloating = true; 499 | g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(n.pWindow); 500 | 501 | // make floating client restore it's position and size 502 | n.pWindow->m_vRealSize = n.ovbk_size; 503 | n.pWindow->m_vRealPosition = n.ovbk_position; 504 | 505 | auto calcPos = n.ovbk_position; 506 | auto calcSize = n.ovbk_size; 507 | 508 | n.pWindow->m_vRealSize = calcSize; 509 | n.pWindow->m_vRealPosition = calcPos; 510 | 511 | g_pXWaylandManager->setWindowSize(n.pWindow, calcSize); 512 | 513 | } else if(!n.ovbk_windowIsFloating && !n.ovbk_windowIsFullscreen) { 514 | // make nofloating client restore it's position and size 515 | n.pWindow->m_vRealSize = n.ovbk_size; 516 | n.pWindow->m_vRealPosition = n.ovbk_position; 517 | 518 | // auto calcPos = n.ovbk_position; 519 | // auto calcSize = n.ovbk_size; 520 | 521 | // n.pWindow->m_vRealSize = calcSize; 522 | // n.pWindow->m_vRealPosition = calcPos; 523 | 524 | // some app sometime can't catch window size to restore,don't use dirty data,remove refer data in old layout. 525 | if (n.ovbk_size.x == 0 && n.ovbk_size.y == 0 && n.isInOldLayout) { 526 | g_hycov_OvGridLayout->removeOldLayoutData(n.pWindow); 527 | n.isInOldLayout = false; 528 | } else { 529 | g_pXWaylandManager->setWindowSize(n.pWindow, n.ovbk_size); 530 | } 531 | 532 | // restore active window in group 533 | if(n.isGroupActive) { 534 | n.pWindow->setGroupCurrent(n.pWindow); 535 | } 536 | } 537 | } 538 | 539 | //exit overview layout,go back to old layout 540 | PHLWINDOW pActiveWindow = g_pCompositor->m_pLastWindow.lock(); 541 | g_pCompositor->focusWindow(nullptr); 542 | // g_pLayoutManager->switchToLayout(*configLayoutName); 543 | // g_pLayoutManager->getCurrentLayout()->onDisable(); 544 | switchToLayoutWithoutReleaseData(*configLayoutName); 545 | recalculateAllMonitor(); 546 | 547 | //Preserve window focus 548 | if(pActiveWindow){ 549 | if(g_hycov_forece_display_all_in_one_monitor && pActiveWindow->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) { 550 | warpcursor_and_focus_to_window(pActiveWindow); //restore the focus to before active window.when cross monitor,warpcursor to monitor of current active window is in 551 | } else { 552 | g_pCompositor->focusWindow(pActiveWindow); //restore the focus to before active window 553 | } 554 | 555 | if(pActiveWindow->m_bIsFloating && g_hycov_raise_float_to_top) { 556 | g_pCompositor->changeWindowZOrder(pActiveWindow, true); 557 | } else if(g_hycov_auto_fullscreen && want_auto_fullscren(pActiveWindow)) { // if enale auto_fullscreen after exit overview 558 | g_pCompositor->setWindowFullscreen(pActiveWindow,true,FULLSCREEN_MAXIMIZED); 559 | } 560 | } 561 | 562 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) 563 | { 564 | //make all fullscrenn windwo restore it's status 565 | if (n.ovbk_windowIsFullscreen) 566 | { 567 | if (!g_pCompositor->m_pLastWindow.lock()) { 568 | continue; 569 | } 570 | 571 | if (n.pWindow != g_pCompositor->m_pLastWindow.lock() && n.pWindow->m_pWorkspace == g_pCompositor->m_pLastWindow.lock()->m_pWorkspace) 572 | { 573 | continue; 574 | } 575 | g_pCompositor->setWindowFullscreen(n.pWindow, true, n.ovbk_windowFullscreenMode ); 576 | } 577 | } 578 | 579 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) 580 | { 581 | // if client not in old layout,create tiling of the client 582 | if(!n.isInOldLayout) 583 | { 584 | if (n.pWindow->m_bFadingOut || !n.pWindow->m_bIsMapped || n.pWindow->isHidden()) { 585 | continue; 586 | } 587 | hycov_log(LOG,"create tiling window in old layout,window:{},workspace:{},inoldlayout:{}",n.pWindow,n.workspaceID,n.isInOldLayout); 588 | g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(n.pWindow); 589 | } 590 | // restore active window in group 591 | if(n.isGroupActive) { 592 | n.pWindow->setGroupCurrent(n.pWindow); 593 | } 594 | } 595 | 596 | //clean overview layout node date 597 | g_hycov_OvGridLayout->m_lOvGridNodesData.clear(); 598 | 599 | //mark has exited overview mode 600 | g_hycov_isOverViewExiting = false; 601 | 602 | // disable hook fullscreenActive funciton 603 | g_hycov_pFullscreenActiveHook->unhook(); 604 | 605 | return; 606 | } 607 | 608 | void registerDispatchers() 609 | { 610 | HyprlandAPI::addDispatcher(PHANDLE, "hycov:enteroverview", dispatch_enteroverview); 611 | HyprlandAPI::addDispatcher(PHANDLE, "hycov:leaveoverview", dispatch_leaveoverview); 612 | HyprlandAPI::addDispatcher(PHANDLE, "hycov:toggleoverview", dispatch_toggleoverview); 613 | HyprlandAPI::addDispatcher(PHANDLE, "hycov:movefocus", dispatch_focusdir); 614 | } 615 | -------------------------------------------------------------------------------- /src/dispatchers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "globals.hpp" 3 | 4 | enum class ShiftDirection { 5 | Left, 6 | Up, 7 | Down, 8 | Right, 9 | }; 10 | 11 | bool want_auto_fullscren(PHLWINDOW pWindow); 12 | bool isDirectionArg(std::string arg); 13 | PHLWINDOW direction_select(std::string arg); 14 | PHLWINDOW get_circle_next_window (std::string arg); 15 | void warpcursor_and_focus_to_window(PHLWINDOW pWindow); 16 | void switchToLayoutWithoutReleaseData(std::string layout); 17 | void recalculateAllMonitor(); 18 | 19 | void dispatch_circle(std::string arg); 20 | void dispatch_focusdir(std::string arg); 21 | 22 | void dispatch_toggleoverview(std::string arg); 23 | void dispatch_enteroverview(std::string arg); 24 | void dispatch_leaveoverview(std::string arg); 25 | 26 | void registerDispatchers(); 27 | -------------------------------------------------------------------------------- /src/globaleventhook.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "globaleventhook.hpp" 3 | #include "dispatchers.hpp" 4 | #include 5 | #include 6 | #include 7 | #include "OvGridLayout.hpp" 8 | 9 | // std::unique_ptr mouseMoveHookPtr = std::make_unique(mouseMoveHook); 10 | // std::unique_ptr mouseButtonHookPtr = std::make_unique(mouseButtonHook); 11 | typedef void (*origOnSwipeBegin)(void*, wlr_pointer_swipe_begin_event* e); 12 | typedef void (*origOnSwipeEnd)(void*, wlr_pointer_swipe_end_event* e); 13 | typedef void (*origOnSwipeUpdate)(void*, wlr_pointer_swipe_update_event* e); 14 | typedef void (*origCWindow_onUnmap)(void*); 15 | typedef void (*origStartAnim)(void*, bool in, bool left, bool instant); 16 | typedef void (*origFullscreenActive)(std::string args); 17 | typedef void (*origOnKeyboardKey)(void*, std::any e, SP pKeyboard); 18 | typedef void (*origCInputManager_onMouseButton)(void*, IPointer::SButtonEvent e); 19 | typedef void (*origCInputManager_mouseMoveUnified)(void* , uint32_t time, bool refocus); 20 | 21 | static double gesture_dx,gesture_previous_dx; 22 | static double gesture_dy,gesture_previous_dy; 23 | 24 | std::string getKeynameFromKeycode(IKeyboard::SKeyEvent e, SP pKeyboard) { 25 | auto keyboard = pKeyboard->wlr(); 26 | xkb_keycode_t keycode = e.keycode + 8; 27 | xkb_keysym_t keysym = xkb_state_key_get_one_sym(keyboard->xkb_state, keycode); 28 | char *tmp_keyname = new char[64]; 29 | xkb_keysym_get_name(keysym, tmp_keyname, 64); 30 | std::string keyname = tmp_keyname; 31 | delete[] tmp_keyname; 32 | return keyname; 33 | } 34 | 35 | bool isKeyReleaseToggleExitOverviewHit(IKeyboard::SKeyEvent e, SP pKeyboard) { 36 | if (g_hycov_alt_replace_key == "") 37 | return false; 38 | 39 | if (isNumber(g_hycov_alt_replace_key) && std::stoi(g_hycov_alt_replace_key) > 9 && std::stoi(g_hycov_alt_replace_key) == (e.keycode + 8)) { 40 | return true; 41 | } else if (g_hycov_alt_replace_key.find("code:") == 0 && isNumber(g_hycov_alt_replace_key.substr(5)) && std::stoi(g_hycov_alt_replace_key.substr(5)) == (e.keycode + 8)) { 42 | return true; 43 | } else { 44 | std::string keyname = getKeynameFromKeycode(e,pKeyboard); 45 | if (keyname == g_hycov_alt_replace_key) { 46 | return true; 47 | } 48 | } 49 | 50 | return false; 51 | } 52 | 53 | static void hkOnSwipeUpdate(void* thisptr, wlr_pointer_swipe_update_event* e) { 54 | if(g_hycov_isOverView){ 55 | gesture_dx = gesture_dx + e->dx; 56 | gesture_dy = gesture_dy + e->dy; 57 | if(e->dx > 0 && gesture_dx - gesture_previous_dx > g_hycov_move_focus_distance){ 58 | dispatch_focusdir("r"); 59 | gesture_previous_dx = gesture_dx; 60 | hycov_log(LOG,"OnSwipeUpdate hook focus right"); 61 | } else if(e->dx < 0 && gesture_previous_dx - gesture_dx > g_hycov_move_focus_distance){ 62 | dispatch_focusdir("l"); 63 | gesture_previous_dx = gesture_dx; 64 | hycov_log(LOG,"OnSwipeUpdate hook focus left"); 65 | } else if(e->dy > 0 && gesture_dy - gesture_previous_dy > g_hycov_move_focus_distance){ 66 | dispatch_focusdir("d"); 67 | gesture_previous_dy = gesture_dy; 68 | hycov_log(LOG,"OnSwipeUpdate hook focus down"); 69 | } else if(e->dy < 0 && gesture_previous_dy - gesture_dy > g_hycov_move_focus_distance){ 70 | dispatch_focusdir("u"); 71 | gesture_previous_dy = gesture_dy; 72 | hycov_log(LOG,"OnSwipeUpdate hook focus up"); 73 | } 74 | return; 75 | } 76 | // call the original function,Let it do what it should do 77 | (*(origOnSwipeUpdate)g_hycov_pOnSwipeUpdateHook->m_pOriginal)(thisptr, e); 78 | } 79 | 80 | static void hkOnSwipeBegin(void* thisptr, wlr_pointer_swipe_begin_event* e) { 81 | if(e->fingers == g_hycov_swipe_fingers){ 82 | g_hycov_isGestureBegin = true; 83 | return; 84 | } 85 | hycov_log(LOG,"OnSwipeBegin hook toggle"); 86 | 87 | // call the original function,Let it do what it should do 88 | (*(origOnSwipeBegin)g_hycov_pOnSwipeBeginHook->m_pOriginal)(thisptr, e); 89 | } 90 | 91 | static void hkOnSwipeEnd(void* thisptr, wlr_pointer_swipe_end_event* e) { 92 | gesture_dx = 0; 93 | gesture_previous_dx = 0; 94 | gesture_dy = 0; 95 | gesture_previous_dy = 0; 96 | 97 | if(g_hycov_isGestureBegin){ 98 | g_hycov_isGestureBegin = false; 99 | dispatch_toggleoverview("internalToggle"); 100 | return; 101 | } 102 | hycov_log(LOG,"OnSwipeEnd hook toggle"); 103 | // call the original function,Let it do what it should do 104 | (*(origOnSwipeEnd)g_hycov_pOnSwipeEndHook->m_pOriginal)(thisptr, e); 105 | } 106 | 107 | static void toggle_hotarea(int x_root, int y_root) 108 | { 109 | CMonitor *pMonitor = g_pCompositor->m_pLastMonitor.get(); 110 | 111 | if (g_hycov_hotarea_monitor != "all" && pMonitor->szName != g_hycov_hotarea_monitor) 112 | return; 113 | 114 | auto m_x = pMonitor->vecPosition.x; 115 | auto m_y = pMonitor->vecPosition.y; 116 | auto m_width = pMonitor->vecSize.x; 117 | auto m_height = pMonitor->vecSize.y; 118 | 119 | if (!g_hycov_isInHotArea && 120 | ((g_hycov_hotarea_pos == 1 && x_root < (m_x + g_hycov_hotarea_size) && y_root > (m_y + m_height - g_hycov_hotarea_size)) || 121 | (g_hycov_hotarea_pos == 2 && x_root > (m_x + m_width - g_hycov_hotarea_size) && y_root > (m_y + m_height - g_hycov_hotarea_size)) || 122 | (g_hycov_hotarea_pos == 3 && x_root < (m_x + g_hycov_hotarea_size) && y_root < (m_y + g_hycov_hotarea_size)) || 123 | (g_hycov_hotarea_pos == 4 && x_root > (m_x + m_width - g_hycov_hotarea_size) && y_root < (m_y + g_hycov_hotarea_size)))) 124 | { 125 | g_hycov_isInHotArea = true; 126 | hycov_log(LOG,"cursor enter hotarea"); 127 | dispatch_toggleoverview("internalToggle"); 128 | } 129 | else if (g_hycov_isInHotArea && 130 | !((g_hycov_hotarea_pos == 1 && x_root < (m_x + g_hycov_hotarea_size) && y_root > (m_y + m_height - g_hycov_hotarea_size)) || 131 | (g_hycov_hotarea_pos == 2 && x_root > (m_x + m_width - g_hycov_hotarea_size) && y_root > (m_y + m_height - g_hycov_hotarea_size)) || 132 | (g_hycov_hotarea_pos == 3 && x_root < (m_x + g_hycov_hotarea_size) && y_root < (m_y + g_hycov_hotarea_size)) || 133 | (g_hycov_hotarea_pos == 4 && x_root > (m_x + m_width - g_hycov_hotarea_size) && y_root < (m_y + g_hycov_hotarea_size)))) 134 | { 135 | g_hycov_isInHotArea = false; 136 | } 137 | } 138 | 139 | static void hkCInputManager_mouseMoveUnified(void* thisptr, uint32_t time, bool refocus) 140 | { 141 | (*(origCInputManager_mouseMoveUnified)g_hycov_pCInputManager_mouseMoveUnifiedHook->m_pOriginal)(thisptr, time, refocus); 142 | 143 | Vector2D mouseCoords = g_pInputManager->getMouseCoordsInternal(); 144 | const auto MOUSECOORDSFLOORED = mouseCoords.floor(); 145 | 146 | toggle_hotarea(MOUSECOORDSFLOORED.x, MOUSECOORDSFLOORED.y); 147 | } 148 | 149 | static void hkCInputManager_onMouseButton(void* thisptr, IPointer::SButtonEvent e) 150 | { 151 | if(g_hycov_isOverView && (e.button == BTN_LEFT || e.button == BTN_RIGHT) ) { 152 | 153 | if (g_hycov_click_in_cursor) { 154 | g_pInputManager->refocus(); 155 | } 156 | 157 | if (!g_pCompositor->m_pLastWindow.lock()) { 158 | return; 159 | } 160 | 161 | switch (e.button) 162 | { 163 | case BTN_LEFT: 164 | if (g_hycov_isOverView && e.state == WL_POINTER_BUTTON_STATE_PRESSED) 165 | { 166 | dispatch_toggleoverview("internalToggle"); 167 | return; 168 | } 169 | break; 170 | case BTN_RIGHT: 171 | if (g_hycov_isOverView && e.state == WL_POINTER_BUTTON_STATE_PRESSED) 172 | { 173 | g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow.lock()); 174 | return; 175 | } 176 | break; 177 | } 178 | } else { 179 | (*(origCInputManager_onMouseButton)g_hycov_pCInputManager_onMouseButtonHook->m_pOriginal)(thisptr, e); 180 | } 181 | } 182 | 183 | 184 | static void hkCWindow_onUnmap(void* thisptr) { 185 | // call the original function,Let it do what it should do 186 | (*(origCWindow_onUnmap)g_hycov_pCWindow_onUnmap->m_pOriginal)(thisptr); 187 | 188 | // after done original thing,The workspace automatically exit overview if no client exists 189 | auto nodeNumInSameMonitor = 0; 190 | auto nodeNumInSameWorkspace = 0; 191 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) { 192 | if(n.pWindow->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && !g_pCompositor->isWorkspaceSpecial(n.workspaceID)) { 193 | nodeNumInSameMonitor++; 194 | } 195 | if(n.pWindow->m_pWorkspace == g_pCompositor->m_pLastMonitor->activeWorkspace) { 196 | nodeNumInSameWorkspace++; 197 | } 198 | } 199 | 200 | if (g_hycov_isOverView && nodeNumInSameMonitor == 0) { 201 | hycov_log(LOG,"no tiling window in same monitor,auto exit overview"); 202 | dispatch_leaveoverview(""); 203 | return; 204 | } 205 | 206 | if (g_hycov_isOverView && nodeNumInSameWorkspace == 0 && (g_hycov_only_active_workspace || g_hycov_force_display_only_current_workspace)) { 207 | hycov_log(LOG,"no tiling windwo in same workspace,auto exit overview"); 208 | dispatch_leaveoverview(""); 209 | return; 210 | } 211 | 212 | } 213 | 214 | static void hkChangeworkspace(std::string args) { 215 | // just log a message and do nothing, mean the original function is disabled 216 | hycov_log(LOG,"ChangeworkspaceHook hook toggle"); 217 | } 218 | 219 | static void hkMoveActiveToWorkspace(std::string args) { 220 | // just log a message and do nothing, mean the original function is disabled 221 | hycov_log(LOG,"MoveActiveToWorkspace hook toggle"); 222 | } 223 | 224 | static void hkSpawn(std::string args) { 225 | // just log a message and do nothing, mean the original function is disabled 226 | hycov_log(LOG,"Spawn hook toggle"); 227 | } 228 | 229 | static void hkStartAnim(void* thisptr,bool in, bool left, bool instant = false) { 230 | // if is exiting overview, omit the animation of workspace change (instant = true) 231 | if (g_hycov_isOverViewExiting) { 232 | (*(origStartAnim)g_hycov_pStartAnimHook->m_pOriginal)(thisptr, in, left, true); 233 | hycov_log(LOG,"hook startAnim,disable workspace change anim,in:{},isOverview:{}",in,g_hycov_isOverView); 234 | } else { 235 | (*(origStartAnim)g_hycov_pStartAnimHook->m_pOriginal)(thisptr, in, left, instant); 236 | // hycov_log(LOG,"hook startAnim,enable workspace change anim,in:{},isOverview:{}",in,g_hycov_isOverView); 237 | } 238 | } 239 | 240 | static void hkOnKeyboardKey(void* thisptr,std::any event, SP pKeyboard) { 241 | 242 | (*(origOnKeyboardKey)g_hycov_pOnKeyboardKeyHook->m_pOriginal)(thisptr, event, pKeyboard); 243 | 244 | auto e = std::any_cast(event); 245 | // hycov_log(LOG,"alt key,keycode:{}",e.keycode); 246 | if(g_hycov_enable_alt_release_exit && g_hycov_isOverView && e.state == WL_KEYBOARD_KEY_STATE_RELEASED) { 247 | if (!isKeyReleaseToggleExitOverviewHit(e,pKeyboard)) 248 | return; 249 | dispatch_leaveoverview(""); 250 | hycov_log(LOG,"alt key release toggle leave overview"); 251 | } 252 | 253 | } 254 | 255 | static void hkFullscreenActive(std::string args) { 256 | // auto exit overview and fullscreen window when toggle fullscreen in overview mode 257 | hycov_log(LOG,"FullscreenActive hook toggle"); 258 | 259 | // (*(origFullscreenActive)g_hycov_pFullscreenActiveHook->m_pOriginal)(args); 260 | const auto pWindow = g_pCompositor->m_pLastWindow.lock(); 261 | 262 | if (!pWindow) 263 | return; 264 | 265 | if (pWindow->m_pWorkspace->m_bIsSpecialWorkspace) 266 | return; 267 | 268 | if (g_hycov_isOverView && want_auto_fullscren(pWindow) && !g_hycov_auto_fullscreen) { 269 | hycov_log(LOG,"FullscreenActive toggle leave overview with fullscreen"); 270 | dispatch_toggleoverview("internalToggle"); 271 | g_pCompositor->setWindowFullscreen(pWindow, !pWindow->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL); 272 | } else if (g_hycov_isOverView && (!want_auto_fullscren(pWindow) || g_hycov_auto_fullscreen)) { 273 | hycov_log(LOG,"FullscreenActive toggle leave overview without fullscreen"); 274 | dispatch_toggleoverview("internalToggle"); 275 | } else { 276 | hycov_log(LOG,"FullscreenActive set fullscreen"); 277 | g_pCompositor->setWindowFullscreen(pWindow, !pWindow->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL); 278 | } 279 | } 280 | 281 | void hkHyprDwindleLayout_recalculateMonitor(void* thisptr,const int& ID) { 282 | ; 283 | } 284 | 285 | void hkHyprMasterLayout_recalculateMonitor(void* thisptr,const int& ID) { 286 | ; 287 | } 288 | 289 | void hkHyprDwindleLayout_recalculateWindow(void* thisptr,CWindow* pWindow) { 290 | ; 291 | } 292 | 293 | void hkSDwindleNodeData_recalcSizePosRecursive(void* thisptr,bool force, bool horizontalOverride, bool verticalOverride) { 294 | ; 295 | } 296 | 297 | void hkCKeybindManager_toggleGroup(std::string args) { 298 | ; 299 | } 300 | 301 | void hkCKeybindManager_moveOutOfGroup(std::string args) { 302 | ; 303 | } 304 | 305 | void hkCKeybindManager_changeGroupActive(std::string args) { 306 | const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); 307 | PHLWINDOW pTargetWindow; 308 | if (!PWINDOW) 309 | return; 310 | 311 | if (!PWINDOW->m_sGroupData.pNextWindow.lock()) 312 | return; 313 | 314 | if (PWINDOW->m_sGroupData.pNextWindow.lock() == PWINDOW) 315 | return; 316 | 317 | auto pNode = g_hycov_OvGridLayout->getNodeFromWindow(PWINDOW); 318 | if (!pNode) 319 | return; 320 | 321 | if (args != "b" && args != "prev") { 322 | pTargetWindow = PWINDOW->m_sGroupData.pNextWindow.lock(); 323 | } else { 324 | pTargetWindow = PWINDOW->getGroupPrevious(); 325 | } 326 | 327 | hycov_log(LOG,"changeGroupActive,pTargetWindow:{}",pTargetWindow); 328 | 329 | if(pNode->isInOldLayout) { // if client is taken from the old layout 330 | g_hycov_OvGridLayout->removeOldLayoutData(PWINDOW); 331 | pNode->isInOldLayout = false; 332 | } 333 | 334 | pNode->pWindow = pTargetWindow; 335 | pNode->pWindow->m_pWorkspace = g_pCompositor->getWorkspaceByID(pNode->workspaceID); 336 | 337 | PWINDOW->setGroupCurrent(pTargetWindow); 338 | g_hycov_OvGridLayout->applyNodeDataToWindow(pNode); 339 | } 340 | 341 | 342 | void registerGlobalEventHook() 343 | { 344 | g_hycov_isInHotArea = false; 345 | g_hycov_isGestureBegin = false; 346 | g_hycov_isOverView = false; 347 | g_hycov_isOverViewExiting = false; 348 | gesture_dx = 0; 349 | gesture_dy = 0; 350 | gesture_previous_dx = 0; 351 | gesture_previous_dy = 0; 352 | 353 | // HyprlandAPI::registerCallbackStatic(PHANDLE, "mouseMove", mouseMoveHookPtr.get()); 354 | // HyprlandAPI::registerCallbackStatic(PHANDLE, "mouseButton", mouseButtonHookPtr.get()); 355 | 356 | //create public function hook 357 | 358 | // hook function of Swipe gesture event handle 359 | g_hycov_pOnSwipeBeginHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CInputManager::onSwipeBegin, (void*)&hkOnSwipeBegin); 360 | g_hycov_pOnSwipeEndHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CInputManager::onSwipeEnd, (void*)&hkOnSwipeEnd); 361 | g_hycov_pOnSwipeUpdateHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CInputManager::onSwipeUpdate, (void*)&hkOnSwipeUpdate); 362 | 363 | // hook function of Gridlayout Remove a node from tiled list 364 | g_hycov_pCWindow_onUnmap = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CWindow::onUnmap, (void*)&hkCWindow_onUnmap); 365 | 366 | // hook function of workspace change animation start 367 | g_hycov_pStartAnimHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CWorkspace::startAnim, (void*)&hkStartAnim); 368 | g_hycov_pStartAnimHook->hook(); 369 | 370 | // hook function of keypress 371 | g_hycov_pOnKeyboardKeyHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CInputManager::onKeyboardKey, (void*)&hkOnKeyboardKey); 372 | 373 | // layotu reculate 374 | g_hycov_pHyprDwindleLayout_recalculateMonitorHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CHyprDwindleLayout::recalculateMonitor, (void*)&hkHyprDwindleLayout_recalculateMonitor); 375 | g_hycov_pHyprMasterLayout_recalculateMonitorHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CHyprMasterLayout::recalculateMonitor, (void*)&hkHyprMasterLayout_recalculateMonitor); 376 | g_hycov_pHyprDwindleLayout_recalculateWindowHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CHyprDwindleLayout::recalculateWindow, (void*)&hkHyprDwindleLayout_recalculateWindow); 377 | g_hycov_pSDwindleNodeData_recalcSizePosRecursiveHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&SDwindleNodeData::recalcSizePosRecursive, (void*)&hkSDwindleNodeData_recalcSizePosRecursive); 378 | 379 | 380 | //mousebutto 381 | g_hycov_pCInputManager_onMouseButtonHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CInputManager::onMouseButton, (void*)&hkCInputManager_onMouseButton); 382 | 383 | 384 | //changeGroupActive 385 | g_hycov_pCKeybindManager_changeGroupActiveHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CKeybindManager::changeGroupActive, (void*)&hkCKeybindManager_changeGroupActive); 386 | 387 | //toggleGroup 388 | g_hycov_pCKeybindManager_toggleGroupHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CKeybindManager::toggleGroup, (void*)&hkCKeybindManager_toggleGroup); 389 | //moveOutOfGroup 390 | g_hycov_pCKeybindManager_moveOutOfGroupHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CKeybindManager::moveOutOfGroup, (void*)&hkCKeybindManager_moveOutOfGroup); 391 | //mouse 392 | g_hycov_pCInputManager_mouseMoveUnifiedHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CInputManager::mouseMoveUnified, (void*)&hkCInputManager_mouseMoveUnified); 393 | 394 | 395 | //create private function hook 396 | 397 | // hook function of changeworkspace 398 | static const auto ChangeworkspaceMethods = HyprlandAPI::findFunctionsByName(PHANDLE, "changeworkspace"); 399 | g_hycov_pChangeworkspaceHook = HyprlandAPI::createFunctionHook(PHANDLE, ChangeworkspaceMethods[0].address, (void*)&hkChangeworkspace); 400 | 401 | // hook function of moveActiveToWorkspace 402 | static const auto MoveActiveToWorkspaceMethods = HyprlandAPI::findFunctionsByName(PHANDLE, "moveActiveToWorkspace"); 403 | g_hycov_pMoveActiveToWorkspaceHook = HyprlandAPI::createFunctionHook(PHANDLE, MoveActiveToWorkspaceMethods[0].address, (void*)&hkMoveActiveToWorkspace); 404 | 405 | // hook function of spawn (bindkey will call spawn to excute a command or a dispatch) 406 | static const auto SpawnMethods = HyprlandAPI::findFunctionsByName(PHANDLE, "spawn"); 407 | g_hycov_pSpawnHook = HyprlandAPI::createFunctionHook(PHANDLE, SpawnMethods[0].address, (void*)&hkSpawn); 408 | 409 | //hook function of fullscreenActive 410 | static const auto FullscreenActiveMethods = HyprlandAPI::findFunctionsByName(PHANDLE, "fullscreenActive"); 411 | g_hycov_pFullscreenActiveHook = HyprlandAPI::createFunctionHook(PHANDLE, FullscreenActiveMethods[0].address, (void*)&hkFullscreenActive); 412 | 413 | //register pEvent hook 414 | if(g_hycov_enable_hotarea){ 415 | g_hycov_pCInputManager_mouseMoveUnifiedHook->hook(); 416 | // static auto mouseMoveHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "mouseMove",[&](void* self, SCallbackInfo& info, std::any data) { hkmouseMove(self, info, data); }); 417 | } 418 | 419 | if(g_hycov_enable_click_action) { 420 | g_hycov_pCInputManager_onMouseButtonHook->hook(); 421 | } 422 | 423 | //if enable gesture, apply hook Swipe function 424 | if(g_hycov_enable_gesture){ 425 | g_hycov_pOnSwipeBeginHook->hook(); 426 | g_hycov_pOnSwipeEndHook->hook(); 427 | g_hycov_pOnSwipeUpdateHook->hook(); 428 | } 429 | 430 | //if enable auto_exit, apply hook RemovedTiling function 431 | if(g_hycov_auto_exit){ 432 | g_hycov_pCWindow_onUnmap->hook(); 433 | } 434 | 435 | //apply hook OnKeyboardKey function 436 | if (g_hycov_enable_alt_release_exit) { 437 | g_hycov_pOnKeyboardKeyHook->hook(); 438 | } 439 | 440 | } 441 | -------------------------------------------------------------------------------- /src/globaleventhook.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void registerGlobalEventHook(); 4 | -------------------------------------------------------------------------------- /src/globals.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "log.hpp" 4 | #include 5 | #include 6 | 7 | #define private public 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #undef private 15 | 16 | #include "OvGridLayout.hpp" 17 | 18 | 19 | inline HANDLE PHANDLE = nullptr; 20 | inline std::unique_ptr g_hycov_OvGridLayout; 21 | 22 | inline bool g_hycov_isOverView; 23 | inline bool g_hycov_isInHotArea; 24 | inline int g_hycov_enable_hotarea; 25 | inline std::string g_hycov_hotarea_monitor; 26 | inline int g_hycov_hotarea_pos; 27 | inline int g_hycov_hotarea_size; 28 | inline unsigned int g_hycov_swipe_fingers; 29 | inline int g_hycov_isGestureBegin; 30 | inline int g_hycov_move_focus_distance; 31 | inline int g_hycov_enable_gesture; 32 | inline int g_hycov_disable_workspace_change; 33 | inline int g_hycov_disable_spawn; 34 | inline int g_hycov_auto_exit; 35 | inline int g_hycov_auto_fullscreen; 36 | inline int g_hycov_only_active_workspace; 37 | inline int g_hycov_only_active_monitor; 38 | inline int g_hycov_enable_alt_release_exit; 39 | inline int g_hycov_alt_toggle_auto_next; 40 | inline int g_hycov_click_in_cursor; 41 | inline int g_hycov_height_of_titlebar; 42 | inline std::string g_hycov_alt_replace_key; 43 | inline int g_hycov_bordersize; 44 | inline int g_hycov_overview_gappo; 45 | inline int g_hycov_overview_gappi; 46 | inline std::string g_hycov_configLayoutName; 47 | inline int g_hycov_show_special; 48 | inline int g_hycov_enable_click_action; 49 | inline int g_hycov_raise_float_to_top; 50 | 51 | 52 | inline bool g_hycov_isOverViewExiting; 53 | inline bool g_hycov_forece_display_all = false; 54 | inline bool g_hycov_forece_display_all_in_one_monitor = false; 55 | inline bool g_hycov_force_display_only_current_workspace = false; 56 | inline int g_hycov_groupBarHeight; 57 | 58 | inline CFunctionHook* g_hycov_pOnSwipeBeginHook = nullptr; 59 | inline CFunctionHook* g_hycov_pOnSwipeEndHook = nullptr; 60 | inline CFunctionHook* g_hycov_pOnSwipeUpdateHook = nullptr; 61 | inline CFunctionHook* g_hycov_pCWindow_onUnmap = nullptr; 62 | inline CFunctionHook* g_hycov_pChangeworkspaceHook = nullptr; 63 | inline CFunctionHook* g_hycov_pMoveActiveToWorkspaceHook = nullptr; 64 | inline CFunctionHook* g_hycov_pSpawnHook = nullptr; 65 | inline CFunctionHook* g_hycov_pStartAnimHook = nullptr; 66 | inline CFunctionHook* g_hycov_pFullscreenActiveHook = nullptr; 67 | inline CFunctionHook* g_hycov_pOnKeyboardKeyHook = nullptr; 68 | inline CFunctionHook* g_hycov_pHyprDwindleLayout_recalculateMonitorHook = nullptr; 69 | inline CFunctionHook* g_hycov_pHyprMasterLayout_recalculateMonitorHook = nullptr; 70 | inline CFunctionHook* g_hycov_pHyprDwindleLayout_recalculateWindowHook = nullptr; 71 | inline CFunctionHook* g_hycov_pSDwindleNodeData_recalcSizePosRecursiveHook = nullptr; 72 | inline CFunctionHook* g_hycov_pCInputManager_onMouseButtonHook = nullptr; 73 | inline CFunctionHook* g_hycov_pCKeybindManager_changeGroupActiveHook = nullptr; 74 | inline CFunctionHook* g_hycov_pCKeybindManager_toggleGroupHook = nullptr; 75 | inline CFunctionHook* g_hycov_pCKeybindManager_moveOutOfGroupHook = nullptr; 76 | inline CFunctionHook* g_hycov_pCInputManager_mouseMoveUnifiedHook = nullptr; 77 | 78 | inline void errorNotif() 79 | { 80 | HyprlandAPI::addNotificationV2( 81 | PHANDLE, 82 | { 83 | {"text", "Something has gone very wrong. Check the log for details."}, 84 | {"time", (uint64_t)10000}, 85 | {"color", CColor(1.0, 0.0, 0.0, 1.0)}, 86 | {"icon", ICON_ERROR}, 87 | }); 88 | } 89 | -------------------------------------------------------------------------------- /src/log.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | void hycov_log(LogLevel level, std::format_string fmt, Args &&...args) 7 | { 8 | auto msg = std::vformat(fmt.get(), std::make_format_args(args...)); 9 | Debug::log(level, "[hycov] {}", msg); 10 | } 11 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "dispatchers.hpp" 4 | #include "globaleventhook.hpp" 5 | 6 | APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; } 7 | 8 | APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) 9 | { 10 | PHANDLE = handle; 11 | 12 | #define CONF(NAME,VALUE) \ 13 | HyprlandAPI::addConfigValue(PHANDLE, "plugin:hycov:" NAME, {VALUE}) 14 | 15 | CONF("overview_gappo", 60L); 16 | CONF("overview_gappi", 24L); 17 | CONF("hotarea_size", 10L); 18 | CONF("hotarea_pos", 1L); 19 | CONF("enable_hotarea", 1L); 20 | CONF("swipe_fingers", 4L); 21 | CONF("move_focus_distance", 100L); 22 | CONF("enable_gesture", 0L); 23 | CONF("disable_workspace_change", 1L); 24 | CONF("disable_spawn", 0L); 25 | CONF("auto_exit", 1L); 26 | CONF("auto_fullscreen", 0L); 27 | CONF("only_active_workspace", 0L); 28 | CONF("only_active_monitor", 0L); 29 | CONF("enable_alt_release_exit", 0L); 30 | CONF("alt_toggle_auto_next", 0L); 31 | CONF("click_in_cursor", 1L); 32 | CONF("height_of_titlebar", 0L); 33 | CONF("hotarea_monitor", "all"); 34 | CONF("alt_replace_key", "Alt_L"); 35 | CONF("show_special", 0L); 36 | CONF("enable_click_action", 1L); 37 | CONF("raise_float_to_top", 1L); 38 | 39 | #undef CONF 40 | 41 | HyprlandAPI::reloadConfig(); 42 | g_pConfigManager->tick(); 43 | 44 | // int value 45 | static const auto *pEnable_hotarea_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:enable_hotarea")->getDataStaticPtr()); 46 | static const auto *pHotarea_pos_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:hotarea_pos")->getDataStaticPtr()); 47 | static const auto *pHotarea_size_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:hotarea_size")->getDataStaticPtr()); 48 | static const auto *pSwipe_fingers_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:swipe_fingers")->getDataStaticPtr()); 49 | static const auto *pMove_focus_distance_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:move_focus_distance")->getDataStaticPtr()); 50 | static const auto *pEnable_gesture_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:enable_gesture")->getDataStaticPtr()); 51 | static const auto *pDisable_workspace_change_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:disable_workspace_change")->getDataStaticPtr()); 52 | static const auto *pDisable_spawn_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:disable_spawn")->getDataStaticPtr()); 53 | static const auto *pAuto_exit_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:auto_exit")->getDataStaticPtr()); 54 | static const auto *pAuto_fullscreen = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:auto_fullscreen")->getDataStaticPtr()); 55 | static const auto *pOnly_active_workspace = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:only_active_workspace")->getDataStaticPtr()); 56 | static const auto *pOnly_active_monitor = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:only_active_monitor")->getDataStaticPtr()); 57 | static const auto *pEnable_alt_release_exit = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:enable_alt_release_exit")->getDataStaticPtr()); 58 | static const auto *pAlt_toggle_auto_next = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:alt_toggle_auto_next")->getDataStaticPtr()); 59 | static const auto *pClick_in_cursor = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:click_in_cursor")->getDataStaticPtr()); 60 | static const auto *pHeight_of_titlebar = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:height_of_titlebar")->getDataStaticPtr()); 61 | static const auto *pBordersize = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->getDataStaticPtr()); 62 | static const auto *pOverview_gappo = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:overview_gappo")->getDataStaticPtr()); 63 | static const auto *pOverview_gappi = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:overview_gappi")->getDataStaticPtr()); 64 | static const auto *pShow_special_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:show_special")->getDataStaticPtr()); 65 | static const auto *pEnable_click_action_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:enable_click_action")->getDataStaticPtr()); 66 | static const auto *pRaise_float_to_top = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:raise_float_to_top")->getDataStaticPtr()); 67 | 68 | 69 | // string value 70 | static const auto *pAlt_replace_key = (Hyprlang::STRING const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:alt_replace_key")->getDataStaticPtr()); 71 | static const auto *pHotarea_monitor_config = (Hyprlang::STRING const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:hotarea_monitor")->getDataStaticPtr()); 72 | static const auto *pConfigLayoutName = (Hyprlang::STRING const*)(HyprlandAPI::getConfigValue(PHANDLE, "general:layout")->getDataStaticPtr()); 73 | static const auto *pGroupBarHeight = (Hyprlang::STRING const*)(HyprlandAPI::getConfigValue(PHANDLE, "group:groupbar:height")->getDataStaticPtr()); 74 | 75 | 76 | // int value 77 | g_hycov_enable_hotarea = **pEnable_hotarea_config; 78 | g_hycov_hotarea_pos = **pHotarea_pos_config; 79 | g_hycov_hotarea_size = **pHotarea_size_config; 80 | g_hycov_swipe_fingers = **pSwipe_fingers_config; 81 | g_hycov_move_focus_distance = **pMove_focus_distance_config; 82 | g_hycov_enable_gesture = **pEnable_gesture_config; 83 | g_hycov_disable_workspace_change = **pDisable_workspace_change_config; 84 | g_hycov_disable_spawn = **pDisable_spawn_config; 85 | g_hycov_auto_exit = **pAuto_exit_config; 86 | g_hycov_auto_fullscreen = **pAuto_fullscreen; 87 | g_hycov_only_active_workspace = **pOnly_active_workspace; 88 | g_hycov_only_active_monitor = **pOnly_active_monitor; 89 | g_hycov_enable_alt_release_exit = **pEnable_alt_release_exit; 90 | g_hycov_alt_toggle_auto_next = **pAlt_toggle_auto_next; 91 | g_hycov_click_in_cursor = **pClick_in_cursor; 92 | g_hycov_height_of_titlebar= **pHeight_of_titlebar; 93 | g_hycov_bordersize = **pBordersize; 94 | g_hycov_overview_gappo = **pOverview_gappo; 95 | g_hycov_overview_gappi = **pOverview_gappi; 96 | g_hycov_show_special = **pShow_special_config; 97 | g_hycov_enable_click_action = **pEnable_click_action_config; 98 | g_hycov_raise_float_to_top = **pRaise_float_to_top; 99 | 100 | 101 | // string value 102 | g_hycov_alt_replace_key = *pAlt_replace_key; 103 | g_hycov_hotarea_monitor = *pHotarea_monitor_config; 104 | g_hycov_configLayoutName = *pConfigLayoutName; 105 | 106 | g_hycov_groupBarHeight= **pGroupBarHeight; 107 | 108 | 109 | g_hycov_OvGridLayout = std::make_unique(); 110 | HyprlandAPI::addLayout(PHANDLE, "ovgrid", g_hycov_OvGridLayout.get()); 111 | 112 | registerGlobalEventHook(); 113 | registerDispatchers(); 114 | 115 | HyprlandAPI::reloadConfig(); 116 | return {"hycov", "overview mode", "DreamMaoMao", "0.3"}; 117 | } 118 | 119 | APICALL EXPORT void PLUGIN_EXIT() {} 120 | --------------------------------------------------------------------------------