├── .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 | 5 | add_compile_definitions(WLR_USE_UNSTABLE) 6 | 7 | find_package(PkgConfig REQUIRED) 8 | pkg_check_modules(DEPS REQUIRED hyprland pixman-1 libdrm pango pangocairo) 9 | 10 | add_library(hycov SHARED 11 | src/main.cpp 12 | src/dispatchers.cpp 13 | src/OvGridLayout.cpp 14 | src/globaleventhook.cpp 15 | ) 16 | 17 | target_include_directories(hycov PRIVATE ${DEPS_INCLUDE_DIRS}) 18 | 19 | # Enable ASan 20 | # target_compile_options(hycov PRIVATE -fsanitize=address -fno-omit-frame-pointer -g -Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith) 21 | # target_link_options(hycov PRIVATE -fsanitize=address) 22 | 23 | install(TARGETS hycov LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) 24 | -------------------------------------------------------------------------------- /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 | # update info 2 | 3 | **for hyprland v 0.4.0** 4 | checkout to tag `v0.4.0` 5 | 6 | **for hyprland v0.45.0** 7 | checkout to tag `v0.45.0` 8 | 9 | **for hyprland v0.45.2^** 10 | in the `main` branch 11 | 12 | no more than hyprland v0.46.1 13 | 14 | # hycov 15 | 16 | A Hyprland overview mode plugin, a new tiling WM workflow. 17 | 18 | > [!NOTE] 19 | > 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. 20 | 21 | ### What can it do? 22 | 23 | - Hycov can tile all of your windows in a single workspace via grid layout. 24 | 25 | - After quitting the overview mode, hycov can perfectly recover a window's previous state (fullscreen, floating, size, positon, etc.) 26 | 27 | - Hycov supports a variety of trigger methods, such as touch pad gestures, hot corners, and keyboard shortcuts. 28 | 29 | - Supports multiple monitors. 30 | 31 | - You can change the way that Hycov focuses a window, whether directional or cyclical. (single-shortcut) 32 | 33 | https://github.com/DreamMaoMao/hycov/assets/30348075/59121362-21a8-4143-be95-72ce79ee8e95 34 | 35 | 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. 36 | 37 | ### Manual Installation 38 | 39 | > [!NOTE] 40 | > 41 | > 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. 42 | > 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). 43 | > 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. 44 | 45 | ##### Using meson and ninja: 46 | 47 | ```shell 48 | git clone https://github.com/DreamMaoMao/hycov.git 49 | cd hycov 50 | sudo meson setup build --prefix=/usr 51 | sudo ninja -C build 52 | sudo ninja -C build install # `libhycov.so` path: /usr/lib/libhycov.so 53 | ``` 54 | 55 | ##### Using CMake: 56 | 57 | ```shell 58 | git clone https://github.com/DreamMaoMao/hycov.git 59 | cd hycov 60 | bash install.sh # `libhycov.so` path: /usr/lib/libhycov.so 61 | ``` 62 | 63 | ##### Using hyprpm: 64 | 65 | ```shell 66 | hyprpm update 67 | hyprpm add https://github.com/DreamMaoMao/hycov 68 | hyprpm enable hycov 69 | ``` 70 | 71 | ### Usage (hyprland.conf) 72 | 73 | ```conf 74 | # When entering overview mode, you can use left-button to jump, right-button to kill or use keybind 75 | 76 | # If you are installing hycov with hyprpm, you should comment out this 77 | plugin = /usr/lib/libhycov.so 78 | 79 | # If you are installing hycov by manually compile , you should comment out this 80 | exec-once = hyprpm reload 81 | 82 | # bind key to toggle overview (normal) 83 | bind = ALT,tab,hycov:toggleoverview 84 | 85 | # bind key to toggle overview (force mode, not affected by `only_active_workspace` or `only_active_monitor`) 86 | bind = ALT,grave,hycov:toggleoverview,forceall #grave key is the '~' key 87 | 88 | # bind key to toggle overview (force mode, not affected by `only_active_workspace` or `only_active_monitor`) 89 | bind = ALT,c,hycov:toggleoverview,onlycurrentworkspace 90 | 91 | # bind key to toggle overview (shows all windows in one monitor, not affected by `only_active_workspace` or `only_active_monitor`) 92 | bind = ALT,g,hycov:toggleoverview,forceallinone 93 | 94 | # The key binding for directional switch mode. 95 | # Calculate the window closest to the direction to switch focus. 96 | # This keybind is applicable not only to the overview, but also to the general layout. 97 | bind=ALT,left,hycov:movefocus,l 98 | bind=ALT,right,hycov:movefocus,r 99 | bind=ALT,up,hycov:movefocus,u 100 | bind=ALT,down,hycov:movefocus,d 101 | 102 | # if you want that focusmove can cross monitor, use this 103 | bind=ALT,left,hycov:movefocus,leftcross 104 | bind=ALT,right,hycov:movefocus,rightcross 105 | bind=ALT,up,hycov:movefocus,upcross 106 | bind=ALT,down,hycov:movefocus,downcross 107 | 108 | plugin { 109 | hycov { 110 | overview_gappo = 60 # gaps width from screen edge 111 | overview_gappi = 24 # gaps width from clients 112 | enable_hotarea = 1 # enable mouse cursor hotarea, when cursor enter hotarea, it will toggle overview 113 | enable_click_action = 1 # enable mouse left button jump and right button kill in overview mode 114 | hotarea_monitor = all # monitor name which hotarea is in, default is all 115 | hotarea_pos = 1 # position of hotarea (1: bottom left, 2: bottom right, 3: top left, 4: top right) 116 | hotarea_size = 10 # hotarea size, 10x10 117 | swipe_fingers = 4 # finger number of gesture,move any directory 118 | move_focus_distance = 100 # distance for movefocus,only can use 3 finger to move 119 | enable_gesture = 0 # enable gesture 120 | auto_exit = 1 # enable auto exit when no client in overview 121 | auto_fullscreen = 0 # auto make active window maximize after exit overview 122 | only_active_workspace = 0 # only overview the active workspace 123 | only_active_monitor = 0 # only overview the active monitor 124 | enable_alt_release_exit = 0 # alt swith mode arg,see readme for detail 125 | alt_replace_key = Alt_L # alt swith mode arg,see readme for detail 126 | alt_toggle_auto_next = 0 # auto focus next window when toggle overview in alt swith mode 127 | click_in_cursor = 1 # when click to jump,the target windwo is find by cursor, not the current foucus window. 128 | hight_of_titlebar = 0 # height deviation of title bar height 129 | show_special = 0 # show windwos in special workspace in overview. 130 | raise_float_to_top = 1 # raise the window that is floating before to top after leave overview mode 131 | } 132 | } 133 | 134 | ``` 135 | 136 | # suggested additional configuration 137 | 138 | - 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. 139 | 140 | ``` 141 | windowrulev2 = bordercolor rgb(158833),fullscreen:1 # set bordercolor to green if window is fullscreen maximize 142 | # toggle fullscreen maximize 143 | bind = ALT,a,fullscreen,1 144 | ``` 145 | 146 |
147 | detail video 148 | 149 | https://github.com/DreamMaoMao/hycov/assets/30348075/15ba36c2-1782-4ae0-8ac1-d0ca98e01e0f 150 | 151 |
152 | 153 | - 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. 154 | 155 | ``` 156 | "hyprland/workspaces": { 157 | "format": "{name}", 158 | "on-click":"activate", 159 | }, 160 | ``` 161 | 162 |
163 | detail picture 164 | 165 | ![image](https://github.com/DreamMaoMao/hycov/assets/30348075/332f4025-20c1-4a44-853b-1b5264df986e) 166 | ![image](https://github.com/DreamMaoMao/hycov/assets/30348075/500d9fd7-299b-48bc-ab72-146f263044a5) 167 | 168 |
169 | 170 | # Alt switch mode 171 | 172 | ```conf 173 | enable_alt_release_exit = 1 174 | alt_toggle_auto_next = 0 # auto focus next window when enter overview in alt mode 175 | # alt_replace_key = Alt_L # If your MainKey of toggleoverview is ALt, you can ignore it 176 | ``` 177 | 178 | ## operation 179 | 180 | such as `alt + tab`: 181 | 182 | - 1.`alt + tab` will enter overview when you not in overview(please hold alt,don't make it release) 183 | 184 | - 2.`alt + tab` will switch window focus circularly when you in overview. (please hold alt,don't make it release) 185 | 186 | - 3.when you release `alt` , it will auto exit overview. 187 | 188 |
189 | If you don't want to use `alt` as MainKey in alt mode 190 | 191 | such as use `super` to repalce `alt` 192 | 193 | - 1.bind toggleoverview 194 | 195 | ``` 196 | bind = SUPER,tab,hycov:toggleoverview 197 | ``` 198 | 199 | - 2.use `alt_replace_key` to specify what is the detection key on release. 200 | 201 | ``` 202 | # use keyname 203 | alt_replace_key = Super_L # Alt_L,Alt_R,Super_L,Super_R,Control_L,Control_R,Shift_L,Shift_R 204 | 205 | # use keycode 206 | alt_replace_key = code:133 # use `xev` command to get keycode 207 | ``` 208 | 209 |
210 | 211 | ### NixOS with home—manager 212 | 213 | ```nix 214 | # flake.nix 215 | 216 | { 217 | inputs = { 218 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 219 | 220 | home-manager = { 221 | url = "github:nix-community/home-manager"; 222 | inputs.nixpkgs.follows = "nixpkgs"; 223 | }; 224 | 225 | hyprland.url = "github:hyprwm/Hyprland"; 226 | 227 | hycov={ 228 | url = "github:DreamMaoMao/hycov"; 229 | inputs.hyprland.follows = "hyprland"; 230 | }; 231 | }; 232 | 233 | outputs = { nixpkgs, home-manager, hyprland, hycov, ... }: 234 | let 235 | system = "x86_64-linux"; 236 | pkgs = nixpkgs.legacyPackages.${system}; 237 | in 238 | { 239 | homeConfigurations."user@hostname" = home-manager.lib.homeManagerConfiguration { 240 | pkgs = nixpkgs.legacyPackages.x86_64-linux; 241 | 242 | modules = [ 243 | hyprland.homeManagerModules.default 244 | { 245 | wayland.windowManager.hyprland = { 246 | enable = true; 247 | package = hyprland.packages."${pkgs.system}".hyprland; 248 | plugins = [ 249 | hycov.packages.${pkgs.system}.hycov 250 | ]; 251 | extraConfig = '' 252 | bind = ALT,tab,hycov:toggleoverview 253 | bind=ALT,left,hycov:movefocus,l 254 | bind=ALT,right,hycov:movefocus,r 255 | bind=ALT,up,hycov:movefocus,u 256 | bind=ALT,down,hycov:movefocus,d 257 | 258 | plugin { 259 | hycov { 260 | overview_gappo = 60 #gaps width from screen 261 | overview_gappi = 24 #gaps width from clients 262 | hotarea_size = 10 #hotarea size in bottom left,10x10 263 | enable_hotarea = 1 # enable mouse cursor hotarea 264 | } 265 | } 266 | '' + '' 267 | # your othor config 268 | ''; 269 | }; 270 | } 271 | # ... 272 | ]; 273 | }; 274 | }; 275 | } 276 | ``` 277 | 278 | ## Frequently Asked Questions 279 | 280 | - some config not work, or the plugin not work. 281 | 282 | ``` 283 | if you use install hycov at first time,please try logout and relogin again. 284 | ``` 285 | 286 | - The numbers on the waybar are confused 287 | 288 | ``` 289 | 1.Please pull the latest waybar source code compilation, 290 | this issue has been fixed in the waybar project, fix date (2023-10-27) 291 | 292 | 2.Change the {id} field in hyprland/workspace field to {name} 293 | ``` 294 | 295 | - Compilation failure 296 | 297 | ``` 298 | Please pull the latest hyprland source code to compile and install. 299 | The plugin relies on a hyprland pr,pr submission date (2023-10-21) 300 | ``` 301 | 302 | - Unable to load 303 | 304 | ``` 305 | Check whether hyprland has been updated, 306 | and if so, please recompile hyprcov 307 | ``` 308 | 309 | - build fail with message `No such file or directory #include ` 310 | 311 | ``` 312 | #step1 313 | yay -R hyprland-git wlroots-git 314 | 315 | #step2 316 | sudo rm -rf /usr/include/hyprland 317 | sudo rm -rf /usr/include/wlr 318 | sudo rm -rf/usr/local/include/hyprland 319 | sudo rm -rf /usr/local/include/wlr 320 | 321 | #step3 322 | yay -S wlroots-git hyprland-git 323 | ``` 324 | 325 | ## Some cool use cases 326 | 327 |
328 | hycov + [hyprland-easymotion](https://github.com/zakk4223/hyprland-easymotion) 329 | 330 | https://github.com/DreamMaoMao/hycov/assets/30348075/486b08f1-be0d-4647-90a3-2029961402cd 331 | 332 | ```conf 333 | bind = ALT,tab, exec, ~/.config/hypr/scripts/hycov-easymotion.sh 334 | submap=__easymotionsubmap__ 335 | bind = ALT, Tab, exec, ~/.config/hypr/scripts/hycov-easymotion.sh 336 | submap=reset 337 | ``` 338 | 339 | ```bash 340 | #!/bin/bash 341 | 342 | workspace_name=$(hyprctl -j activeworkspace | jq -r '.name') 343 | 344 | if [ "$workspace_name" = "OVERVIEW" ]; then 345 | hyprctl dispatch hycov:leaveoverview 346 | else 347 | hyprctl dispatch hycov:enteroverview 348 | hyprctl dispatch 'easymotion action:hyprctl --batch "dispatch focuswindow address:{} ; dispatch hycov:leaveoverview"' 349 | fi 350 | ``` 351 | 352 |
353 | -------------------------------------------------------------------------------- /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 | "aquamarine": { 4 | "inputs": { 5 | "hyprutils": [ 6 | "hyprland", 7 | "hyprutils" 8 | ], 9 | "hyprwayland-scanner": [ 10 | "hyprland", 11 | "hyprwayland-scanner" 12 | ], 13 | "nixpkgs": [ 14 | "hyprland", 15 | "nixpkgs" 16 | ], 17 | "systems": [ 18 | "hyprland", 19 | "systems" 20 | ] 21 | }, 22 | "locked": { 23 | "lastModified": 1734906446, 24 | "narHash": "sha256-6OWluVE2A8xi+8V3jN9KA72RCgJjYdyyuLBUjxZ2q2U=", 25 | "owner": "hyprwm", 26 | "repo": "aquamarine", 27 | "rev": "eecb74dc79bb6752a2a507e6edee3042390a6091", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "hyprwm", 32 | "repo": "aquamarine", 33 | "type": "github" 34 | } 35 | }, 36 | "flake-compat": { 37 | "flake": false, 38 | "locked": { 39 | "lastModified": 1696426674, 40 | "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", 41 | "owner": "edolstra", 42 | "repo": "flake-compat", 43 | "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", 44 | "type": "github" 45 | }, 46 | "original": { 47 | "owner": "edolstra", 48 | "repo": "flake-compat", 49 | "type": "github" 50 | } 51 | }, 52 | "gitignore": { 53 | "inputs": { 54 | "nixpkgs": [ 55 | "hyprland", 56 | "pre-commit-hooks", 57 | "nixpkgs" 58 | ] 59 | }, 60 | "locked": { 61 | "lastModified": 1709087332, 62 | "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", 63 | "owner": "hercules-ci", 64 | "repo": "gitignore.nix", 65 | "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", 66 | "type": "github" 67 | }, 68 | "original": { 69 | "owner": "hercules-ci", 70 | "repo": "gitignore.nix", 71 | "type": "github" 72 | } 73 | }, 74 | "hyprcursor": { 75 | "inputs": { 76 | "hyprlang": [ 77 | "hyprland", 78 | "hyprlang" 79 | ], 80 | "nixpkgs": [ 81 | "hyprland", 82 | "nixpkgs" 83 | ], 84 | "systems": [ 85 | "hyprland", 86 | "systems" 87 | ] 88 | }, 89 | "locked": { 90 | "lastModified": 1734906540, 91 | "narHash": "sha256-vQ/L9hZFezC0LquLo4TWXkyniWtYBlFHAKIsDc7PYJE=", 92 | "owner": "hyprwm", 93 | "repo": "hyprcursor", 94 | "rev": "69270ba8f057d55b0e6c2dca0e165d652856e613", 95 | "type": "github" 96 | }, 97 | "original": { 98 | "owner": "hyprwm", 99 | "repo": "hyprcursor", 100 | "type": "github" 101 | } 102 | }, 103 | "hyprgraphics": { 104 | "inputs": { 105 | "hyprutils": [ 106 | "hyprland", 107 | "hyprutils" 108 | ], 109 | "nixpkgs": [ 110 | "hyprland", 111 | "nixpkgs" 112 | ], 113 | "systems": [ 114 | "hyprland", 115 | "systems" 116 | ] 117 | }, 118 | "locked": { 119 | "lastModified": 1734906236, 120 | "narHash": "sha256-vH/ysV2ONGQgYZPtcJKwc8jJivzyVxru2aaOxC20ZOE=", 121 | "owner": "hyprwm", 122 | "repo": "hyprgraphics", 123 | "rev": "6dea3fba08fd704dd624b6d4b261638fb4003c9c", 124 | "type": "github" 125 | }, 126 | "original": { 127 | "owner": "hyprwm", 128 | "repo": "hyprgraphics", 129 | "type": "github" 130 | } 131 | }, 132 | "hyprland": { 133 | "inputs": { 134 | "aquamarine": "aquamarine", 135 | "hyprcursor": "hyprcursor", 136 | "hyprgraphics": "hyprgraphics", 137 | "hyprland-protocols": "hyprland-protocols", 138 | "hyprland-qtutils": "hyprland-qtutils", 139 | "hyprlang": "hyprlang", 140 | "hyprutils": "hyprutils", 141 | "hyprwayland-scanner": "hyprwayland-scanner", 142 | "nixpkgs": "nixpkgs", 143 | "pre-commit-hooks": "pre-commit-hooks", 144 | "systems": "systems", 145 | "xdph": "xdph" 146 | }, 147 | "locked": { 148 | "lastModified": 1735585949, 149 | "narHash": "sha256-vCGG4tGMvzCzz+ZIsiNtpoFW9+f+itYLTAVW41qk/Hk=", 150 | "ref": "refs/heads/main", 151 | "rev": "1989b0049f7fb714a2417dfb14d6b4f3d2a079d3", 152 | "revCount": 5607, 153 | "submodules": true, 154 | "type": "git", 155 | "url": "https://github.com/hyprwm/Hyprland" 156 | }, 157 | "original": { 158 | "submodules": true, 159 | "type": "git", 160 | "url": "https://github.com/hyprwm/Hyprland" 161 | } 162 | }, 163 | "hyprland-protocols": { 164 | "inputs": { 165 | "nixpkgs": [ 166 | "hyprland", 167 | "nixpkgs" 168 | ], 169 | "systems": [ 170 | "hyprland", 171 | "systems" 172 | ] 173 | }, 174 | "locked": { 175 | "lastModified": 1728345020, 176 | "narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=", 177 | "owner": "hyprwm", 178 | "repo": "hyprland-protocols", 179 | "rev": "a7c183800e74f337753de186522b9017a07a8cee", 180 | "type": "github" 181 | }, 182 | "original": { 183 | "owner": "hyprwm", 184 | "repo": "hyprland-protocols", 185 | "type": "github" 186 | } 187 | }, 188 | "hyprland-qtutils": { 189 | "inputs": { 190 | "hyprutils": [ 191 | "hyprland", 192 | "hyprutils" 193 | ], 194 | "nixpkgs": [ 195 | "hyprland", 196 | "nixpkgs" 197 | ], 198 | "systems": [ 199 | "hyprland", 200 | "systems" 201 | ] 202 | }, 203 | "locked": { 204 | "lastModified": 1734906472, 205 | "narHash": "sha256-pWPRv/GA/X/iAwoE6gMNUqn/ZeJX1IeLPRpZI0tTPK0=", 206 | "owner": "hyprwm", 207 | "repo": "hyprland-qtutils", 208 | "rev": "c77109d7e1ddbcdb87cafd32ce411f76328ae152", 209 | "type": "github" 210 | }, 211 | "original": { 212 | "owner": "hyprwm", 213 | "repo": "hyprland-qtutils", 214 | "type": "github" 215 | } 216 | }, 217 | "hyprlang": { 218 | "inputs": { 219 | "hyprutils": [ 220 | "hyprland", 221 | "hyprutils" 222 | ], 223 | "nixpkgs": [ 224 | "hyprland", 225 | "nixpkgs" 226 | ], 227 | "systems": [ 228 | "hyprland", 229 | "systems" 230 | ] 231 | }, 232 | "locked": { 233 | "lastModified": 1734906259, 234 | "narHash": "sha256-P79t/7HbACO4/PuJBroGpTptvCWJtXTv+gWsF+sM6MI=", 235 | "owner": "hyprwm", 236 | "repo": "hyprlang", 237 | "rev": "0404833ea18d543df44df935ebf1b497310eb046", 238 | "type": "github" 239 | }, 240 | "original": { 241 | "owner": "hyprwm", 242 | "repo": "hyprlang", 243 | "type": "github" 244 | } 245 | }, 246 | "hyprutils": { 247 | "inputs": { 248 | "nixpkgs": [ 249 | "hyprland", 250 | "nixpkgs" 251 | ], 252 | "systems": [ 253 | "hyprland", 254 | "systems" 255 | ] 256 | }, 257 | "locked": { 258 | "lastModified": 1735316583, 259 | "narHash": "sha256-AiiUwHWHfEdpFzXy7l1x3zInCUa1xcRMrbZ1XRSkzwU=", 260 | "owner": "hyprwm", 261 | "repo": "hyprutils", 262 | "rev": "8f15d45b120b33712f6db477fe5ffb18034d0ea8", 263 | "type": "github" 264 | }, 265 | "original": { 266 | "owner": "hyprwm", 267 | "repo": "hyprutils", 268 | "type": "github" 269 | } 270 | }, 271 | "hyprwayland-scanner": { 272 | "inputs": { 273 | "nixpkgs": [ 274 | "hyprland", 275 | "nixpkgs" 276 | ], 277 | "systems": [ 278 | "hyprland", 279 | "systems" 280 | ] 281 | }, 282 | "locked": { 283 | "lastModified": 1734793513, 284 | "narHash": "sha256-rrrHcXapXJvGFqX+L/Bb0182L25jofAZ0fm1FInvrTQ=", 285 | "owner": "hyprwm", 286 | "repo": "hyprwayland-scanner", 287 | "rev": "4d7367b6eee87397e2dbca2e78078dd0a4ef4c61", 288 | "type": "github" 289 | }, 290 | "original": { 291 | "owner": "hyprwm", 292 | "repo": "hyprwayland-scanner", 293 | "type": "github" 294 | } 295 | }, 296 | "nixpkgs": { 297 | "locked": { 298 | "lastModified": 1735291276, 299 | "narHash": "sha256-NYVcA06+blsLG6wpAbSPTCyLvxD/92Hy4vlY9WxFI1M=", 300 | "owner": "NixOS", 301 | "repo": "nixpkgs", 302 | "rev": "634fd46801442d760e09493a794c4f15db2d0cbb", 303 | "type": "github" 304 | }, 305 | "original": { 306 | "owner": "NixOS", 307 | "ref": "nixos-unstable", 308 | "repo": "nixpkgs", 309 | "type": "github" 310 | } 311 | }, 312 | "nixpkgs-stable": { 313 | "locked": { 314 | "lastModified": 1730741070, 315 | "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", 316 | "owner": "NixOS", 317 | "repo": "nixpkgs", 318 | "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", 319 | "type": "github" 320 | }, 321 | "original": { 322 | "owner": "NixOS", 323 | "ref": "nixos-24.05", 324 | "repo": "nixpkgs", 325 | "type": "github" 326 | } 327 | }, 328 | "pre-commit-hooks": { 329 | "inputs": { 330 | "flake-compat": "flake-compat", 331 | "gitignore": "gitignore", 332 | "nixpkgs": [ 333 | "hyprland", 334 | "nixpkgs" 335 | ], 336 | "nixpkgs-stable": "nixpkgs-stable" 337 | }, 338 | "locked": { 339 | "lastModified": 1734797603, 340 | "narHash": "sha256-ulZN7ps8nBV31SE+dwkDvKIzvN6hroRY8sYOT0w+E28=", 341 | "owner": "cachix", 342 | "repo": "git-hooks.nix", 343 | "rev": "f0f0dc4920a903c3e08f5bdb9246bb572fcae498", 344 | "type": "github" 345 | }, 346 | "original": { 347 | "owner": "cachix", 348 | "repo": "git-hooks.nix", 349 | "type": "github" 350 | } 351 | }, 352 | "root": { 353 | "inputs": { 354 | "hyprland": "hyprland", 355 | "nixpkgs": [ 356 | "hyprland", 357 | "nixpkgs" 358 | ], 359 | "systems": [ 360 | "hyprland", 361 | "systems" 362 | ] 363 | } 364 | }, 365 | "systems": { 366 | "locked": { 367 | "lastModified": 1689347949, 368 | "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", 369 | "owner": "nix-systems", 370 | "repo": "default-linux", 371 | "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", 372 | "type": "github" 373 | }, 374 | "original": { 375 | "owner": "nix-systems", 376 | "repo": "default-linux", 377 | "type": "github" 378 | } 379 | }, 380 | "xdph": { 381 | "inputs": { 382 | "hyprland-protocols": [ 383 | "hyprland", 384 | "hyprland-protocols" 385 | ], 386 | "hyprlang": [ 387 | "hyprland", 388 | "hyprlang" 389 | ], 390 | "hyprutils": [ 391 | "hyprland", 392 | "hyprutils" 393 | ], 394 | "hyprwayland-scanner": [ 395 | "hyprland", 396 | "hyprwayland-scanner" 397 | ], 398 | "nixpkgs": [ 399 | "hyprland", 400 | "nixpkgs" 401 | ], 402 | "systems": [ 403 | "hyprland", 404 | "systems" 405 | ] 406 | }, 407 | "locked": { 408 | "lastModified": 1734907020, 409 | "narHash": "sha256-p6HxwpRKVl1KIiY5xrJdjcEeK3pbmc///UOyV6QER+w=", 410 | "owner": "hyprwm", 411 | "repo": "xdg-desktop-portal-hyprland", 412 | "rev": "d7f18dda5e511749fa1511185db3536208fb1a63", 413 | "type": "github" 414 | }, 415 | "original": { 416 | "owner": "hyprwm", 417 | "repo": "xdg-desktop-portal-hyprland", 418 | "type": "github" 419 | } 420 | } 421 | }, 422 | "root": "root", 423 | "version": 7 424 | } 425 | -------------------------------------------------------------------------------- /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.gcc14Stdenv; 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.gcc14Stdenv; } { 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 "OvGridLayout.hpp" 3 | #include "dispatchers.hpp" 4 | #include "globals.hpp" 5 | #include "src/SharedDefs.hpp" 6 | #include "src/desktop/Workspace.hpp" 7 | #include "src/helpers/Monitor.hpp" 8 | #include "src/managers/EventManager.hpp" 9 | #include "src/managers/LayoutManager.hpp" 10 | #include "src/render/Renderer.hpp" 11 | 12 | // find next focus window after remove a window 13 | PHLWINDOW OvGridLayout::getNextWindowCandidate(PHLWINDOW plastWindow) { 14 | 15 | PHLWINDOW targetWindow = nullptr; 16 | for (auto &w : g_pCompositor->m_windows) { 17 | PHLWINDOW pWindow = w; 18 | if (pWindow->m_workspace != plastWindow->m_workspace || 19 | pWindow->isHidden() || !pWindow->m_isMapped || pWindow->m_fadingOut || 20 | pWindow->isFullscreen()) 21 | continue; 22 | targetWindow = pWindow; // find the last window that is in same workspace 23 | // with the remove window 24 | } 25 | 26 | return targetWindow; 27 | } 28 | 29 | SOvGridNodeData *OvGridLayout::getNodeFromWindow(PHLWINDOW pWindow) { 30 | for (auto &nd : m_lOvGridNodesData) { 31 | if (nd.pWindow == pWindow) 32 | return &nd; 33 | } 34 | 35 | return nullptr; 36 | } 37 | 38 | SOldLayoutRecordNodeData * 39 | OvGridLayout::getOldLayoutRecordNodeFromWindow(PHLWINDOW pWindow) { 40 | for (auto &nd : m_lSOldLayoutRecordNodeData) { 41 | if (nd.pWindow == pWindow) 42 | return &nd; 43 | } 44 | 45 | return nullptr; 46 | } 47 | 48 | int OvGridLayout::getNodesNumOnWorkspace(const int &ws) { 49 | int no = 0; 50 | for (auto &n : m_lOvGridNodesData) { 51 | if (n.workspaceID == ws) 52 | no++; 53 | } 54 | 55 | return no; 56 | } 57 | 58 | Vector2D OvGridLayout::predictSizeForNewWindowTiled() { return {}; } 59 | 60 | void OvGridLayout::resizeNodeSizePos(SOvGridNodeData *node, int x, int y, 61 | int width, int height) { 62 | 63 | int groupbar_height_fix; 64 | if (node->pWindow->m_groupData.pNextWindow.lock()) { 65 | groupbar_height_fix = g_hycov_groupBarHeight; 66 | } else { 67 | groupbar_height_fix = 0; 68 | } 69 | node->size = Vector2D(width, height - g_hycov_height_of_titlebar - 70 | groupbar_height_fix); 71 | node->position = 72 | Vector2D(x, y + g_hycov_height_of_titlebar + groupbar_height_fix); 73 | applyNodeDataToWindow(node); 74 | } 75 | 76 | void OvGridLayout::onWindowCreatedTiling(PHLWINDOW pWindow, 77 | eDirection direction) { 78 | CMonitor *pTargetMonitor; 79 | if (g_hycov_forece_display_all_in_one_monitor) { 80 | pTargetMonitor = g_pCompositor->m_lastMonitor.get(); 81 | } else { 82 | pTargetMonitor = 83 | g_pCompositor->getMonitorFromID(pWindow->monitorID()).get(); 84 | } 85 | 86 | const auto pNode = 87 | &m_lOvGridNodesData.emplace_back(); // make a new node in list back 88 | 89 | auto pActiveWorkspace = pTargetMonitor->m_activeWorkspace; 90 | 91 | auto pWindowOriWorkspace = pWindow->m_workspace; 92 | 93 | auto oldLayoutRecordNode = getOldLayoutRecordNodeFromWindow(pWindow); 94 | if (oldLayoutRecordNode) { 95 | pNode->isInOldLayout = true; // client is taken from the old layout 96 | m_lSOldLayoutRecordNodeData.remove(*oldLayoutRecordNode); 97 | } 98 | 99 | // record the previcous window in group 100 | if (pWindow->m_groupData.pNextWindow.lock() && 101 | pWindow->getGroupCurrent() == pWindow) { 102 | pNode->isGroupActive = true; 103 | } 104 | 105 | pNode->workspaceID = 106 | pWindow->workspaceID(); // encapsulate window objects as node objects to 107 | // bind more properties 108 | pNode->pWindow = pWindow; 109 | pNode->workspaceName = pWindowOriWorkspace->m_name; 110 | 111 | // record the window stats which are used by restore 112 | pNode->ovbk_windowMonitorId = pWindow->monitorID(); 113 | pNode->ovbk_windowWorkspaceId = pWindow->workspaceID(); 114 | pNode->ovbk_windowFullscreenMode = pWindowOriWorkspace->m_fullscreenMode; 115 | pNode->ovbk_position = pWindow->m_realPosition->goal(); 116 | pNode->ovbk_size = pWindow->m_realSize->goal(); 117 | pNode->ovbk_windowIsFloating = pWindow->m_isFloating; 118 | pNode->ovbk_windowIsFullscreen = pWindow->isFullscreen(); 119 | pNode->ovbk_windowWorkspaceName = pWindowOriWorkspace->m_name; 120 | 121 | // change all client(exclude special workspace) to active worksapce 122 | if ((!g_pCompositor->isWorkspaceSpecial(pNode->workspaceID) || 123 | g_hycov_show_special) && 124 | pNode->isInOldLayout && 125 | (pWindowOriWorkspace->m_id != pActiveWorkspace->m_id || 126 | pWindowOriWorkspace->m_name != pActiveWorkspace->m_name) && 127 | (!(g_hycov_only_active_workspace || 128 | g_hycov_force_display_only_current_workspace) || 129 | g_hycov_forece_display_all || 130 | g_hycov_forece_display_all_in_one_monitor)) { 131 | pWindow->m_workspace = pActiveWorkspace; 132 | pNode->workspaceID = pWindow->workspaceID(); 133 | pNode->workspaceName = pActiveWorkspace->m_name; 134 | pNode->pWindow->m_monitor = 135 | g_pCompositor->getMonitorFromID(pTargetMonitor->m_id); 136 | } 137 | 138 | // clean fullscreen status 139 | if (pWindow->isFullscreen()) { 140 | pWindow->m_fullscreenState = {.internal = FSMODE_NONE, 141 | .client = FSMODE_FULLSCREEN}; 142 | } 143 | 144 | // clean floating status(only apply to old layout window) 145 | if (pWindow->m_isFloating && pNode->isInOldLayout) { 146 | pWindow->m_isFloating = false; 147 | pWindow->updateDynamicRules(); 148 | } 149 | 150 | recalculateMonitor(pWindow->monitorID()); 151 | } 152 | 153 | void OvGridLayout::removeOldLayoutData(PHLWINDOW pWindow) { 154 | 155 | std::string *configLayoutName = &g_hycov_configLayoutName; 156 | switchToLayoutWithoutReleaseData(*configLayoutName); 157 | hycov_log(LOG, "remove data of old layout:{}", *configLayoutName); 158 | 159 | if (*configLayoutName == "dwindle") { 160 | // disable render client of old layout 161 | g_hycov_pHyprDwindleLayout_recalculateMonitorHook->hook(); 162 | g_hycov_pHyprDwindleLayout_recalculateWindowHook->hook(); 163 | g_hycov_pSDwindleNodeData_recalcSizePosRecursiveHook->hook(); 164 | 165 | // only remove data,not render anything,becaust still in overview 166 | g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); 167 | 168 | g_hycov_pSDwindleNodeData_recalcSizePosRecursiveHook->unhook(); 169 | g_hycov_pHyprDwindleLayout_recalculateWindowHook->unhook(); 170 | g_hycov_pHyprDwindleLayout_recalculateMonitorHook->unhook(); 171 | } else if (*configLayoutName == "master") { 172 | g_hycov_pHyprMasterLayout_recalculateMonitorHook->hook(); 173 | 174 | g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); 175 | 176 | g_hycov_pHyprMasterLayout_recalculateMonitorHook->unhook(); 177 | } else { 178 | // may be not support other layout 179 | hycov_log(ERR, "unknow old layout:{}", *configLayoutName); 180 | g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); 181 | } 182 | 183 | switchToLayoutWithoutReleaseData("ovgrid"); 184 | } 185 | 186 | void OvGridLayout::onWindowRemoved(PHLWINDOW pWindow) { 187 | const auto pNode = getNodeFromWindow(pWindow); 188 | 189 | if (!pNode) 190 | return; 191 | 192 | if (pNode->isInOldLayout) { // if client is taken from the old layout 193 | removeOldLayoutData(pWindow); 194 | } 195 | 196 | if (pWindow->isFullscreen()) 197 | g_pCompositor->setWindowFullscreenState( 198 | pWindow, {.internal = FSMODE_NONE, .client = FSMODE_FULLSCREEN}); 199 | 200 | if (!pWindow->m_groupData.pNextWindow.expired()) { 201 | if (pWindow->m_groupData.pNextWindow.lock() == pWindow) 202 | pWindow->m_groupData.pNextWindow.reset(); 203 | else { 204 | // find last window and update 205 | PHLWINDOW PWINDOWPREV = pWindow->getGroupPrevious(); 206 | const auto WINDOWISVISIBLE = pWindow->getGroupCurrent() == pWindow; 207 | 208 | if (WINDOWISVISIBLE) 209 | PWINDOWPREV->setGroupCurrent( 210 | pWindow->m_groupData.head ? pWindow->m_groupData.pNextWindow.lock() 211 | : PWINDOWPREV); 212 | 213 | PWINDOWPREV->m_groupData.pNextWindow = pWindow->m_groupData.pNextWindow; 214 | 215 | pWindow->m_groupData.pNextWindow.reset(); 216 | 217 | if (pWindow->m_groupData.head) { 218 | std::swap(PWINDOWPREV->m_groupData.pNextWindow.lock()->m_groupData.head, 219 | pWindow->m_groupData.head); 220 | std::swap( 221 | PWINDOWPREV->m_groupData.pNextWindow.lock()->m_groupData.locked, 222 | pWindow->m_groupData.locked); 223 | } 224 | 225 | // if (pWindow == m_pLastTiledWindow.lock()) 226 | // m_pLastTiledWindow.reset(); 227 | 228 | pWindow->setHidden(false); 229 | 230 | pWindow->updateWindowDecos(); 231 | PWINDOWPREV->getGroupCurrent()->updateWindowDecos(); 232 | g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); 233 | 234 | // change node bind window in group 235 | pNode->pWindow = PWINDOWPREV->getGroupCurrent(); 236 | pNode->pWindow->m_workspace = 237 | g_pCompositor->m_lastMonitor->m_activeWorkspace; 238 | applyNodeDataToWindow(pNode); 239 | pNode->isInOldLayout = false; 240 | hycov_log(LOG, "change node bind window in group,old:{} new:{}", pWindow, 241 | pNode->pWindow); 242 | 243 | return; 244 | } 245 | } 246 | 247 | if (pWindow->m_isFloating) { 248 | onWindowRemovedFloating(pWindow); 249 | } else { 250 | onWindowRemovedTiling(pWindow); 251 | } 252 | 253 | // if (pWindow == m_pLastTiledWindow.lock()) 254 | // m_pLastTiledWindow.reset(); 255 | } 256 | 257 | void OvGridLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { 258 | hycov_log(LOG, "remove tiling windwo:{}", pWindow); 259 | 260 | const auto pNode = getNodeFromWindow(pWindow); 261 | 262 | if (!pNode) 263 | return; 264 | 265 | if (pNode->isInOldLayout) { // if client is taken from the old layout 266 | removeOldLayoutData(pWindow); 267 | } 268 | 269 | // if window is in a group,replace it with other window in same group 270 | // pNode->pWindow->m_workspace = 271 | // g_pCompositor->getWorkspaceByID(pNode->workspaceID); 272 | // applyNodeDataToWindow(pNode); 273 | // pNode->isInOldLayout = false; 274 | // g_pCompositor->focusWindow(pNode->pWindow); 275 | // return; 276 | // } 277 | 278 | m_lOvGridNodesData.remove(*pNode); 279 | 280 | if (m_lOvGridNodesData.empty()) { 281 | return; 282 | } 283 | 284 | recalculateMonitor(pWindow->monitorID()); 285 | } 286 | 287 | bool OvGridLayout::isWindowTiled(PHLWINDOW pWindow) { 288 | return getNodeFromWindow(pWindow) != nullptr; 289 | } 290 | 291 | void OvGridLayout::calculateWorkspace(const int &ws) { 292 | const auto pWorksapce = g_pCompositor->getWorkspaceByID(ws); 293 | auto dataSize = m_lOvGridNodesData.size(); 294 | auto pTempNodes = new SOvGridNodeData *[dataSize + 1]; 295 | SOvGridNodeData *pNode; 296 | int i, n = 0; 297 | int cx, cy; 298 | int dx, cw, ch; 299 | ; 300 | int cols, rows, overcols, NODECOUNT; 301 | 302 | if (!pWorksapce) { 303 | delete[] pTempNodes; 304 | return; 305 | } 306 | 307 | NODECOUNT = getNodesNumOnWorkspace(pWorksapce->m_id); 308 | const auto pMonitor = 309 | g_pCompositor->getMonitorFromID(pWorksapce->monitorID()); 310 | 311 | if (NODECOUNT == 0) { 312 | delete[] pTempNodes; 313 | return; 314 | } 315 | 316 | static const auto *PBORDERSIZE = &g_hycov_bordersize; 317 | static const auto *GAPPO = &g_hycov_overview_gappo; 318 | static const auto *GAPPI = &g_hycov_overview_gappi; 319 | 320 | /* 321 | m is region that is moniotr, 322 | w is region that is monitor but don not contain bar 323 | */ 324 | int m_x = pMonitor->m_position.x; 325 | int m_y = pMonitor->m_position.y; 326 | int w_x = pMonitor->m_position.x + pMonitor->m_position.x; 327 | int w_y = pMonitor->m_position.y + pMonitor->m_position.y; 328 | int m_width = pMonitor->m_size.x; 329 | int m_height = pMonitor->m_size.y; 330 | int w_width = pMonitor->m_size.x - pMonitor->m_reservedTopLeft.x; 331 | int w_height = pMonitor->m_size.y - pMonitor->m_reservedTopLeft.y; 332 | 333 | for (auto &node : m_lOvGridNodesData) { 334 | if (node.workspaceID == ws) { 335 | pTempNodes[n] = &node; 336 | n++; 337 | } 338 | } 339 | 340 | pTempNodes[n] = NULL; 341 | 342 | if (NODECOUNT == 0) { 343 | delete[] pTempNodes; 344 | return; 345 | } 346 | 347 | // one client arrange 348 | if (NODECOUNT == 1) { 349 | pNode = pTempNodes[0]; 350 | cw = (w_width - 2 * (*GAPPO)) * 0.7; 351 | ch = (w_height - 2 * (*GAPPO)) * 0.8; 352 | resizeNodeSizePos(pNode, w_x + (int)((m_width - cw) / 2), 353 | w_y + (int)((w_height - ch) / 2), cw - 2 * (*PBORDERSIZE), 354 | ch - 2 * (*PBORDERSIZE)); 355 | delete[] pTempNodes; 356 | return; 357 | } 358 | 359 | // two client arrange 360 | if (NODECOUNT == 2) { 361 | pNode = pTempNodes[1]; 362 | cw = (w_width - 2 * (*GAPPO) - (*GAPPI)) / 2; 363 | ch = (w_height - 2 * (*GAPPO)) * 0.65; 364 | resizeNodeSizePos(pNode, m_x + cw + (*GAPPO) + (*GAPPI), 365 | m_y + (m_height - ch) / 2 + (*GAPPO), 366 | cw - 2 * (*PBORDERSIZE), ch - 2 * (*PBORDERSIZE)); 367 | resizeNodeSizePos(pTempNodes[0], m_x + (*GAPPO), 368 | m_y + (m_height - ch) / 2 + (*GAPPO), 369 | cw - 2 * (*PBORDERSIZE), ch - 2 * (*PBORDERSIZE)); 370 | delete[] pTempNodes; 371 | return; 372 | } 373 | 374 | // more than two client arrange 375 | 376 | // Calculate the integer part of the square root of the number of nodes 377 | for (cols = 0; cols <= NODECOUNT / 2; cols++) 378 | if (cols * cols >= NODECOUNT) 379 | break; 380 | 381 | // The number of rows and columns multiplied by the number of nodes 382 | // must be greater than the number of nodes to fit all the Windows 383 | rows = (cols && (cols - 1) * cols >= NODECOUNT) ? cols - 1 : cols; 384 | 385 | // Calculate the width and height of the layout area based on 386 | // the number of rows and columns 387 | ch = (int)((w_height - 2 * (*GAPPO) - (rows - 1) * (*GAPPI)) / rows); 388 | cw = (int)((w_width - 2 * (*GAPPO) - (cols - 1) * (*GAPPI)) / cols); 389 | 390 | // If the nodes do not exactly fill all rows, 391 | // the number of Windows in the unfilled rows is 392 | overcols = NODECOUNT % cols; 393 | 394 | if (overcols) 395 | dx = (int)((w_width - overcols * cw - (overcols - 1) * (*GAPPI)) / 2) - 396 | (*GAPPO); 397 | for (i = 0, pNode = pTempNodes[0]; pNode; pNode = pTempNodes[i + 1], i++) { 398 | cx = w_x + (i % cols) * (cw + (*GAPPI)); 399 | cy = w_y + (int)(i / cols) * (ch + (*GAPPI)); 400 | if (overcols && i >= (NODECOUNT - overcols)) { 401 | cx += dx; 402 | } 403 | resizeNodeSizePos(pNode, cx + (*GAPPO), cy + (*GAPPO), 404 | cw - 2 * (*PBORDERSIZE), ch - 2 * (*PBORDERSIZE)); 405 | } 406 | delete[] pTempNodes; 407 | } 408 | 409 | void OvGridLayout::recalculateMonitor(const MONITORID &monid) { 410 | const auto pMonitor = 411 | g_pCompositor->getMonitorFromID(monid); // 根据monitor id获取monitor对象 412 | 413 | if (!pMonitor || !pMonitor->m_activeWorkspace) 414 | return; 415 | // if (pMonitor->m_size.x <= 0 || pMonitor->m_size.y <= 0) { 416 | // Debug::log(ERR, "Invalid monitor size: width={}, height={}", 417 | // pMonitor->m_size.x, pMonitor->m_size.y); 418 | // return; 419 | // } 420 | // return; 421 | g_pHyprRenderer->damageMonitor(pMonitor); // Use local rendering 422 | 423 | if (pMonitor->activeSpecialWorkspaceID()) { 424 | calculateWorkspace(pMonitor->activeSpecialWorkspaceID()); 425 | return; 426 | } 427 | 428 | const auto pWorksapce = g_pCompositor->getWorkspaceByID( 429 | pMonitor->activeWorkspaceID()); // 获取当前workspace对象 430 | if (!pWorksapce) 431 | return; 432 | 433 | calculateWorkspace(pWorksapce->m_id); // calculate windwo's size and position 434 | } 435 | 436 | // set window's size and position 437 | void OvGridLayout::applyNodeDataToWindow(SOvGridNodeData *pNode) { 438 | 439 | const auto pWindow = pNode->pWindow; 440 | 441 | // force disable decorate and shadow 442 | // pWindow->m_sSpecialRenderData.decorate = false; 443 | // pWindow->m_sSpecialRenderData.shadow = false; 444 | 445 | // force enable bordear and rounding 446 | 447 | pWindow->m_size = pNode->size; 448 | pWindow->m_position = pNode->position; 449 | 450 | auto calcPos = pWindow->m_position; 451 | auto calcSize = pWindow->m_size; 452 | 453 | pWindow->m_realSize->value() = calcSize; 454 | pWindow->m_realPosition->value() = calcPos; 455 | // g_pXWaylandManager->setWindowSize(pWindow, calcSize); 456 | 457 | pWindow->updateWindowDecos(); 458 | } 459 | 460 | void OvGridLayout::recalculateWindow(PHLWINDOW pWindow) { 461 | ; // empty 462 | } 463 | 464 | void OvGridLayout::resizeActiveWindow(const Vector2D &pixResize, 465 | eRectCorner corner, PHLWINDOW pWindow) { 466 | ; // empty 467 | } 468 | 469 | void OvGridLayout::fullscreenRequestForWindow( 470 | PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, 471 | const eFullscreenMode EFFECTIVE_MODE) { 472 | ; // empty 473 | } 474 | 475 | std::any OvGridLayout::layoutMessage(SLayoutMessageHeader header, 476 | std::string content) { 477 | return ""; 478 | } 479 | 480 | SWindowRenderLayoutHints OvGridLayout::requestRenderHints(PHLWINDOW pWindow) { 481 | return {}; 482 | } 483 | 484 | void OvGridLayout::switchWindows(PHLWINDOW pWindowA, PHLWINDOW pWindowB) { 485 | ; // empty 486 | } 487 | 488 | void OvGridLayout::alterSplitRatio(PHLWINDOW pWindow, float delta, bool exact) { 489 | ; // empty 490 | } 491 | 492 | std::string OvGridLayout::getLayoutName() { return "ovgrid"; } 493 | 494 | void OvGridLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) { 495 | ; // empty 496 | } 497 | 498 | void OvGridLayout::moveWindowTo(PHLWINDOW, const std::string &dir, 499 | bool silent) { 500 | ; // empty 501 | } 502 | 503 | void OvGridLayout::changeToActivceSourceWorkspace() { 504 | PHLWINDOW pWindow = nullptr; 505 | SOvGridNodeData *pNode; 506 | PHLWORKSPACE pWorksapce; 507 | hycov_log(LOG, "changeToActivceSourceWorkspace"); 508 | pWindow = g_pCompositor->m_lastWindow.lock(); 509 | pNode = getNodeFromWindow(pWindow); 510 | if (pNode) { 511 | pWorksapce = g_pCompositor->getWorkspaceByID(pNode->ovbk_windowWorkspaceId); 512 | } else if (pWindow) { 513 | pWorksapce = pWindow->m_workspace; 514 | } else { 515 | pWorksapce = g_pCompositor->m_lastMonitor->m_activeWorkspace; 516 | } 517 | // pMonitor->changeWorkspace(pWorksapce); 518 | hycov_log(LOG, "changeToWorkspace:{}", pWorksapce->m_id); 519 | g_pEventManager->postEvent(SHyprIPCEvent{"workspace", pWorksapce->m_name}); 520 | // EMIT_HOOK_EVENT("workspace", pWorksapce); 521 | } 522 | 523 | void OvGridLayout::moveWindowToSourceWorkspace() { 524 | PHLWORKSPACE pWorkspace; 525 | 526 | hycov_log(LOG, "moveWindowToSourceWorkspace"); 527 | 528 | for (auto &nd : m_lOvGridNodesData) { 529 | if (nd.pWindow && 530 | (nd.pWindow->m_workspace->m_id != nd.ovbk_windowWorkspaceId || 531 | nd.workspaceName != nd.ovbk_windowWorkspaceName)) { 532 | pWorkspace = g_pCompositor->getWorkspaceByID(nd.ovbk_windowWorkspaceId); 533 | if (!pWorkspace) { 534 | hycov_log(LOG, "source workspace no exist"); 535 | g_hycov_pSpawnHook->hook(); // disable on-emptty-create workspace rule 536 | pWorkspace = g_pCompositor->createNewWorkspace( 537 | nd.ovbk_windowWorkspaceId, nd.ovbk_windowMonitorId, 538 | nd.ovbk_windowWorkspaceName); 539 | g_hycov_pSpawnHook->unhook(); 540 | } 541 | nd.pWindow->m_monitor->m_id = nd.ovbk_windowMonitorId; 542 | nd.pWindow->m_workspace = pWorkspace; 543 | nd.workspaceID = nd.ovbk_windowWorkspaceId; 544 | nd.workspaceName = nd.ovbk_windowWorkspaceName; 545 | nd.pWindow->m_position = nd.ovbk_position; 546 | nd.pWindow->m_size = nd.ovbk_size; 547 | g_pHyprRenderer->damageWindow(nd.pWindow); 548 | } 549 | } 550 | } 551 | 552 | // it will exec once when change layout enable 553 | void OvGridLayout::onEnable() { 554 | 555 | for (auto &w : g_pCompositor->m_windows) { 556 | PHLWINDOW pWindow = w; 557 | if (pWindow->isHidden() || !pWindow->m_isMapped || pWindow->m_fadingOut) 558 | continue; 559 | 560 | if (pWindow->monitorID() != g_pCompositor->m_lastMonitor->m_id && 561 | g_hycov_only_active_monitor && !g_hycov_forece_display_all && 562 | !g_hycov_forece_display_all_in_one_monitor) 563 | continue; 564 | 565 | const auto pNode = &m_lSOldLayoutRecordNodeData.emplace_back(); 566 | pNode->pWindow = pWindow; 567 | onWindowCreatedTiling(pWindow); 568 | } 569 | } 570 | 571 | // it will exec once when change layout disable 572 | void OvGridLayout::onDisable() { dispatch_leaveoverview(""); } 573 | -------------------------------------------------------------------------------- /src/OvGridLayout.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | struct SOvGridNodeData 9 | { 10 | PHLWINDOW pWindow = nullptr; 11 | int ovbk_windowWorkspaceId = -1; 12 | std::string ovbk_windowWorkspaceName; 13 | int ovbk_windowMonitorId = -1; 14 | std::string workspaceName; 15 | bool ovbk_windowIsFloating = false; 16 | bool ovbk_windowIsFullscreen = false; 17 | eFullscreenMode ovbk_windowFullscreenMode ; 18 | Vector2D ovbk_position; 19 | Vector2D ovbk_size; 20 | Vector2D position; 21 | Vector2D size; 22 | bool ovbk_windowIsWithBorder; 23 | bool ovbk_windowIsWithDecorate; 24 | bool ovbk_windowIsWithRounding; 25 | bool ovbk_windowIsWithShadow; 26 | bool isInOldLayout = false; 27 | bool isGroupActive = false; 28 | 29 | int workspaceID = -1; 30 | 31 | bool operator==(const SOvGridNodeData &rhs) const 32 | { 33 | return pWindow == rhs.pWindow; 34 | } 35 | }; 36 | 37 | 38 | struct SOldLayoutRecordNodeData 39 | { 40 | PHLWINDOW pWindow = nullptr; 41 | bool operator==(const SOldLayoutRecordNodeData &rhs) const 42 | { 43 | return pWindow == rhs.pWindow; 44 | } 45 | }; 46 | 47 | 48 | class OvGridLayout : public IHyprLayout 49 | { 50 | public: 51 | virtual void onWindowCreatedTiling(PHLWINDOW , eDirection direction = DIRECTION_DEFAULT); 52 | virtual void onWindowRemovedTiling(PHLWINDOW ); 53 | virtual void onWindowRemoved(PHLWINDOW ); 54 | virtual bool isWindowTiled(PHLWINDOW ); 55 | virtual PHLWINDOW getNextWindowCandidate(PHLWINDOW); 56 | virtual void recalculateMonitor(const MONITORID &); 57 | virtual void recalculateWindow(PHLWINDOW ); 58 | virtual void resizeActiveWindow(const Vector2D &, eRectCorner corner, PHLWINDOW pWindow = nullptr); 59 | virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE); 60 | virtual std::any layoutMessage(SLayoutMessageHeader, std::string); 61 | virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW ); 62 | virtual void switchWindows(PHLWINDOW , PHLWINDOW ); 63 | virtual void alterSplitRatio(PHLWINDOW , float, bool); 64 | virtual std::string getLayoutName(); 65 | virtual Vector2D predictSizeForNewWindowTiled(); 66 | virtual void replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to); 67 | virtual void moveWindowTo(PHLWINDOW, const std::string& direction, bool silent = false); 68 | virtual void onEnable(); 69 | virtual void onDisable(); 70 | void applyNodeDataToWindow(SOvGridNodeData *); 71 | void calculateWorkspace(const int &); 72 | int getNodesNumOnWorkspace(const int &); 73 | SOvGridNodeData *getNodeFromWindow(PHLWINDOW ); 74 | SOldLayoutRecordNodeData *getOldLayoutRecordNodeFromWindow(PHLWINDOW ); 75 | void resizeNodeSizePos(SOvGridNodeData *, int, int, int, int); 76 | void moveWindowToWorkspaceSilent(PHLWINDOW , const int &); 77 | std::list m_lOvGridNodesData; 78 | std::list m_lSOldLayoutRecordNodeData; 79 | void moveWindowToSourceWorkspace(); 80 | void changeToActivceSourceWorkspace(); 81 | void removeOldLayoutData(PHLWINDOW pWindow); 82 | private: 83 | }; 84 | -------------------------------------------------------------------------------- /src/dispatchers.cpp: -------------------------------------------------------------------------------- 1 | #include "dispatchers.hpp" 2 | #include "src/helpers/Monitor.hpp" 3 | #include "src/managers/LayoutManager.hpp" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static const std::string overviewWorksapceName = "OVERVIEW"; 10 | static std::string workspaceNameBackup; 11 | static int workspaceIdBackup; 12 | 13 | void recalculateAllMonitor() { 14 | for (auto &m : g_pCompositor->m_monitors) { 15 | CMonitor *pMonitor = m.get(); 16 | g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->m_id); 17 | } 18 | } 19 | 20 | // only change layout,keep data of previous layout 21 | void switchToLayoutWithoutReleaseData(std::string layout) { 22 | // for (size_t i = 0; i < g_pLayoutManager->getAllLayoutNames().size(); ++i) { 23 | // if (g_pLayoutManager->getAllLayoutNames()[i] == layout) { 24 | // if (i == (size_t)g_pLayoutManager->getCurrentLayout()->getLayoutName()) 25 | // return; 26 | // g_pLayoutManager->m_iCurrentLayoutID = i; 27 | // return; 28 | // } 29 | // } 30 | g_pLayoutManager->switchToLayout(layout); 31 | hycov_log(ERR, "Unknown layout!"); 32 | } 33 | 34 | bool want_auto_fullscren(PHLWINDOW pWindow) { 35 | int nodeNumInTargetWorkspace = 1; 36 | 37 | if(!pWindow) { 38 | return false; 39 | } 40 | 41 | auto pNode = g_hycov_OvGridLayout->getNodeFromWindow(pWindow); 42 | 43 | if(!pNode) { 44 | return true; 45 | } 46 | 47 | // if client is fullscreen before,don't make it fullscreen 48 | if (pNode->ovbk_windowIsFullscreen) { 49 | return false; 50 | } 51 | 52 | // caculate the number of clients that will be in the same workspace with pWindow(don't contain itself) 53 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) { 54 | if(n.pWindow != pNode->pWindow && n.ovbk_windowWorkspaceId == pNode->ovbk_windowWorkspaceId) { 55 | nodeNumInTargetWorkspace++; 56 | } 57 | } 58 | 59 | // if only one client in workspace(pWindow itself), don't make it fullscreen 60 | if(nodeNumInTargetWorkspace > 1) { 61 | return true; 62 | } else { 63 | return false; 64 | } 65 | } 66 | 67 | bool isDirectionArg(std::string arg) { 68 | 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") { 69 | return true; 70 | } else { 71 | return false; 72 | } 73 | } 74 | 75 | bool isCrossMonitor(std::string arg) { 76 | if (arg == "leftcross" || arg == "rightcross" || arg == "upcross" || arg == "downcross") { 77 | return true; 78 | } else { 79 | return false; 80 | } 81 | } 82 | 83 | std::optional parseShiftArg(std::string arg) { 84 | if (arg == "l" || arg == "left" || arg == "leftcross") return ShiftDirection::Left; 85 | else if (arg == "r" || arg == "right" || arg == "rightcross") return ShiftDirection::Right; 86 | else if (arg == "u" || arg == "up" || arg == "upcross") return ShiftDirection::Up; 87 | else if (arg == "d" || arg == "down" || arg == "downcross") return ShiftDirection::Down; 88 | else return {}; 89 | } 90 | 91 | PHLWINDOW direction_select(std::string arg){ 92 | PHLWINDOW pTempClient = g_pCompositor->m_lastWindow.lock(); 93 | auto dataSize = g_pCompositor->m_windows.size(); 94 | auto pTempCWindows = new PHLWINDOW[dataSize + 1]; 95 | PHLWINDOW pTempFocusCWindows = nullptr; 96 | int last = -1; 97 | if(!pTempClient){ 98 | delete[] pTempCWindows; 99 | return nullptr; 100 | }else if (pTempClient->isFullscreen()){ 101 | delete[] pTempCWindows; 102 | return nullptr; 103 | } 104 | 105 | if (!isDirectionArg(arg)) { 106 | hycov_log(ERR, "Cannot move focus in direction {}, unsupported direction. Supported: l/left/leftcross,r/right/rightcross,u/up/upcross,d/down/downcross", arg); 107 | delete[] pTempCWindows; 108 | return nullptr; 109 | } 110 | 111 | for (auto &w : g_pCompositor->m_windows) 112 | { 113 | PHLWINDOW pWindow = w; 114 | 115 | if (pTempClient == pWindow || pWindow->isHidden() || !pWindow->m_isMapped || pWindow->m_fadingOut || pWindow->isFullscreen()) { 116 | continue; 117 | } 118 | 119 | auto *pMonitor = g_pCompositor->getMonitorFromID(pWindow->monitorID()).get(); 120 | 121 | if (!((isCrossMonitor(arg) && pWindow->m_monitor->m_id != pTempClient->m_monitor->m_id && !pTempClient->m_workspace->m_isSpecialWorkspace && pWindow->m_workspace == pMonitor->m_activeWorkspace) || pTempClient->m_workspace == pWindow->m_workspace)) { 122 | continue; 123 | } 124 | 125 | last++; 126 | pTempCWindows[last] = pWindow; 127 | } 128 | 129 | if (last < 0) { 130 | delete[] pTempCWindows; 131 | return nullptr; 132 | } 133 | int sel_x = pTempClient->m_realPosition->goal().x; 134 | int sel_y = pTempClient->m_realPosition->goal().y; 135 | long long int distance = LLONG_MAX;; 136 | // int temp_focus = 0; 137 | 138 | auto values = CVarList(arg); 139 | auto shift = parseShiftArg(values[0]); 140 | switch (shift.value()) { 141 | case ShiftDirection::Up: 142 | // Find the window with the closest coordinates 143 | // in the top left corner of the window (is limited to same x) 144 | for (int _i = 0; _i <= last; _i++) { 145 | if (pTempCWindows[_i]->m_realPosition->goal().y < sel_y && pTempCWindows[_i]->m_realPosition->goal().x == sel_x) { 146 | int dis_x = pTempCWindows[_i]->m_realPosition->goal().x - sel_x; 147 | int dis_y = pTempCWindows[_i]->m_realPosition->goal().y - sel_y; 148 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 149 | if (tmp_distance < distance) { 150 | distance = tmp_distance; 151 | pTempFocusCWindows = pTempCWindows[_i]; 152 | } 153 | } 154 | } 155 | // if find nothing above 156 | // find again(is unlimited to x) 157 | if(!pTempFocusCWindows){ 158 | for (int _i = 0; _i <= last; _i++) { 159 | if (pTempCWindows[_i]->m_realPosition->goal().y < sel_y ) { 160 | int dis_x = pTempCWindows[_i]->m_realPosition->goal().x - sel_x; 161 | int dis_y = pTempCWindows[_i]->m_realPosition->goal().y - sel_y; 162 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 163 | if (tmp_distance < distance) { 164 | distance = tmp_distance; 165 | pTempFocusCWindows = pTempCWindows[_i]; 166 | } 167 | } 168 | } 169 | } 170 | break; 171 | case ShiftDirection::Down: 172 | for (int _i = 0; _i <= last; _i++) { 173 | if (pTempCWindows[_i]->m_realPosition->goal().y > sel_y && pTempCWindows[_i]->m_realPosition->goal().x == sel_x) { 174 | int dis_x = pTempCWindows[_i]->m_realPosition->goal().x - sel_x; 175 | int dis_y = pTempCWindows[_i]->m_realPosition->goal().y - sel_y; 176 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 177 | if (tmp_distance < distance) { 178 | distance = tmp_distance; 179 | pTempFocusCWindows = pTempCWindows[_i]; 180 | } 181 | } 182 | } 183 | if(!pTempFocusCWindows){ 184 | for (int _i = 0; _i <= last; _i++) { 185 | if (pTempCWindows[_i]->m_realPosition->goal().y > sel_y ) { 186 | int dis_x = pTempCWindows[_i]->m_realPosition->goal().x - sel_x; 187 | int dis_y = pTempCWindows[_i]->m_realPosition->goal().y - sel_y; 188 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 189 | if (tmp_distance < distance) { 190 | distance = tmp_distance; 191 | pTempFocusCWindows = pTempCWindows[_i]; 192 | } 193 | } 194 | } 195 | } 196 | break; 197 | case ShiftDirection::Left: 198 | for (int _i = 0; _i <= last; _i++) { 199 | if (pTempCWindows[_i]->m_realPosition->goal().x < sel_x && pTempCWindows[_i]->m_realPosition->goal().y == sel_y) { 200 | int dis_x = pTempCWindows[_i]->m_realPosition->goal().x - sel_x; 201 | int dis_y = pTempCWindows[_i]->m_realPosition->goal().y - sel_y; 202 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 203 | if (tmp_distance < distance) { 204 | distance = tmp_distance; 205 | pTempFocusCWindows = pTempCWindows[_i]; 206 | } 207 | } 208 | } 209 | if(!pTempFocusCWindows){ 210 | for (int _i = 0; _i <= last; _i++) { 211 | if (pTempCWindows[_i]->m_realPosition->goal().x < sel_x) { 212 | int dis_x = pTempCWindows[_i]->m_realPosition->goal().x - sel_x; 213 | int dis_y = pTempCWindows[_i]->m_realPosition->goal().y - sel_y; 214 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 215 | if (tmp_distance < distance) { 216 | distance = tmp_distance; 217 | pTempFocusCWindows = pTempCWindows[_i]; 218 | } 219 | } 220 | } 221 | } 222 | break; 223 | case ShiftDirection::Right: 224 | for (int _i = 0; _i <= last; _i++) { 225 | auto placeholder = pTempCWindows[_i]->m_realPosition; 226 | if (pTempCWindows[_i]->m_realPosition->goal().x > sel_x && 227 | placeholder->goal().y == sel_y) { 228 | int dis_x = pTempCWindows[_i]->m_realPosition->goal().x - sel_x; 229 | int dis_y = pTempCWindows[_i]->m_realPosition->goal().y - sel_y; 230 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 231 | if (tmp_distance < distance) { 232 | distance = tmp_distance; 233 | pTempFocusCWindows = pTempCWindows[_i]; 234 | } 235 | } 236 | } 237 | if(!pTempFocusCWindows){ 238 | for (int _i = 0; _i <= last; _i++) { 239 | if (pTempCWindows[_i]->m_realPosition->goal().x > sel_x) { 240 | int dis_x = pTempCWindows[_i]->m_realPosition->goal().x - sel_x; 241 | int dis_y = pTempCWindows[_i]->m_realPosition->goal().y - sel_y; 242 | long long int tmp_distance = dis_x * dis_x + dis_y * dis_y; 243 | if (tmp_distance < distance) { 244 | distance = tmp_distance; 245 | pTempFocusCWindows = pTempCWindows[_i]; 246 | } 247 | } 248 | } 249 | } 250 | break; 251 | } 252 | delete[] pTempCWindows; 253 | return pTempFocusCWindows; 254 | } 255 | 256 | PHLWINDOW get_circle_next_window (std::string arg) { 257 | bool next_ready = false; 258 | PHLWINDOW pTempClient = g_pCompositor->m_lastWindow.lock(); 259 | 260 | if(!pTempClient) 261 | return nullptr; 262 | 263 | for (auto &w : g_pCompositor->m_windows) 264 | { 265 | PHLWINDOW pWindow = w; 266 | if (pTempClient->m_workspace != pWindow->m_workspace || pWindow->isHidden() || !pWindow->m_isMapped || pWindow->m_fadingOut || pWindow->isFullscreen()) 267 | continue; 268 | if (next_ready) 269 | return pWindow; 270 | if (pWindow == pTempClient) 271 | next_ready = true; 272 | } 273 | 274 | for (auto &w : g_pCompositor->m_windows) 275 | { 276 | PHLWINDOW pWindow = w; 277 | if (pTempClient->m_workspace != pWindow->m_workspace || pWindow->isHidden() || !pWindow->m_isMapped || pWindow->m_fadingOut || pWindow->isFullscreen()) 278 | continue; 279 | return pWindow; 280 | } 281 | return nullptr; 282 | } 283 | 284 | void warpcursor_and_focus_to_window(PHLWINDOW pWindow) { 285 | g_pCompositor->focusWindow(pWindow); 286 | g_pCompositor->warpCursorTo(pWindow->middle()); 287 | } 288 | 289 | void dispatch_circle(std::string arg) 290 | { 291 | PHLWINDOW pWindow; 292 | pWindow = get_circle_next_window(arg); 293 | if(pWindow){ 294 | warpcursor_and_focus_to_window(pWindow); 295 | } 296 | } 297 | 298 | void dispatch_focusdir(std::string arg) 299 | { 300 | PHLWINDOW pWindow; 301 | pWindow = direction_select(arg); 302 | if(pWindow){ 303 | warpcursor_and_focus_to_window(pWindow); 304 | } 305 | } 306 | 307 | void dispatch_toggleoverview(std::string arg) 308 | { 309 | if (g_hycov_isOverView && (!g_hycov_enable_alt_release_exit || arg == "internalToggle")) { 310 | dispatch_leaveoverview(""); 311 | hycov_log(LOG,"leave overview:toggleMethod:{},enable_alt_release_exit:{}",arg,g_hycov_enable_alt_release_exit); 312 | } else if (g_hycov_isOverView && g_hycov_enable_alt_release_exit && arg != "internalToggle") { 313 | dispatch_circle(""); 314 | hycov_log(LOG,"toggle overview:switch focus circlely"); 315 | } else if(g_hycov_enable_alt_release_exit && g_hycov_alt_toggle_auto_next && arg != "internalToggle") { 316 | dispatch_enteroverview(arg); 317 | dispatch_circle(""); 318 | hycov_log(LOG,"enter overview:alt switch mode auto next"); 319 | } else { 320 | dispatch_enteroverview(arg); 321 | hycov_log(LOG,"enter overview:toggleMethod:{}",arg); 322 | } 323 | } 324 | 325 | 326 | void dispatch_enteroverview(std::string arg) 327 | { 328 | if(g_hycov_isOverView) { 329 | return; 330 | } 331 | 332 | const auto pMonitor = g_pCompositor->m_lastMonitor; 333 | if(pMonitor->activeSpecialWorkspaceID() != 0) 334 | pMonitor->setSpecialWorkspace(nullptr); 335 | 336 | //force display all workspace window,ignore `only_active_worksapce` and `only_active_monitor` 337 | if (arg == "forceall") { 338 | g_hycov_forece_display_all = true; 339 | hycov_log(LOG,"force display all clients"); 340 | } else { 341 | g_hycov_forece_display_all = false; 342 | } 343 | 344 | //force display all workspace window in one monitor,ignore `only_active_worksapce` and `only_active_monitor` 345 | if (arg == "forceallinone") { 346 | g_hycov_forece_display_all_in_one_monitor = true; 347 | hycov_log(LOG,"force display all clients in one monitor"); 348 | } else { 349 | g_hycov_forece_display_all_in_one_monitor = false; 350 | } 351 | 352 | //force only display current workspace,ignore `only_active_worksapce` and `only_active_monitor` 353 | if (arg == "onlycurrentworkspace") { 354 | g_hycov_force_display_only_current_workspace = true; 355 | hycov_log(LOG,"force display only current workspace"); 356 | } else { 357 | g_hycov_force_display_only_current_workspace = false; 358 | } 359 | 360 | //ali clients exit fullscreen status before enter overview 361 | PHLWINDOW pFullscreenWindow; 362 | PHLWINDOW pActiveWindow = g_pCompositor->m_lastWindow.lock(); 363 | PHLWORKSPACE pActiveWorkspace; 364 | CMonitor *pActiveMonitor; 365 | 366 | bool isNoShouldTileWindow = true; 367 | 368 | for (auto &w : g_pCompositor->m_windows) 369 | { 370 | PHLWINDOW pWindow = w; 371 | if (pWindow->isHidden() || !pWindow->m_isMapped || pWindow->m_fadingOut || pWindow->m_workspace->m_isSpecialWorkspace) 372 | continue; 373 | isNoShouldTileWindow = false; 374 | } 375 | 376 | //if no clients, forbit enter overview 377 | if(isNoShouldTileWindow){ 378 | return; 379 | } 380 | 381 | hycov_log(LOG,"enter overview"); 382 | g_hycov_isOverView = true; 383 | 384 | //make all fullscreen window exit fullscreen state 385 | for (auto &w : g_pCompositor->m_workspaces) 386 | { 387 | CWorkspace *pWorkspace = w.get(); 388 | if (pWorkspace->m_hasFullscreenWindow) 389 | { 390 | pFullscreenWindow = pWorkspace->getFullscreenWindow(); 391 | g_pCompositor->setWindowFullscreenState(pFullscreenWindow, { .internal = FSMODE_NONE, .client = FSMODE_FULLSCREEN }); 392 | 393 | //let overview know the client is a fullscreen before 394 | pFullscreenWindow->m_fullscreenState = { .internal = FSMODE_NONE, .client = FSMODE_FULLSCREEN }; 395 | } 396 | } 397 | 398 | //enter overview layout 399 | // g_pLayoutManager->switchToLayout("ovgrid"); 400 | switchToLayoutWithoutReleaseData("ovgrid"); 401 | //g_pLayoutManager->getCurrentLayout()->onEnable(); 402 | 403 | //change workspace name to OVERVIEW 404 | pActiveMonitor = g_pCompositor->m_lastMonitor.get(); 405 | pActiveWorkspace = g_pCompositor->getWorkspaceByID(pActiveMonitor->m_activeWorkspace->m_id); 406 | workspaceNameBackup = pActiveWorkspace->m_name; 407 | workspaceIdBackup = pActiveWorkspace->m_id; 408 | g_pCompositor->getWorkspaceByID(workspaceIdBackup)->m_name = std::move(overviewWorksapceName); 409 | 410 | //Preserve window focus 411 | if(pActiveWindow){ 412 | g_pCompositor->focusWindow(pActiveWindow); //restore the focus to before active window 413 | 414 | } else { // when no window is showed in current window,find from other workspace to focus(exclude special workspace) 415 | for (auto &w : g_pCompositor->m_windows) { 416 | PHLWINDOW pWindow = w; 417 | auto node = g_hycov_OvGridLayout->getNodeFromWindow(pWindow); 418 | if ( !node || g_pCompositor->isWorkspaceSpecial(node->workspaceID) || pWindow->isHidden() || !pWindow->m_isMapped || pWindow->m_fadingOut || pWindow->isFullscreen()) 419 | continue; 420 | g_pCompositor->focusWindow(pWindow); // find the last window that is in same workspace with the remove window 421 | } 422 | 423 | } 424 | 425 | // enable hook fullscreenActive funciton 426 | g_hycov_pFullscreenActiveHook->hook(); 427 | 428 | //disable changeworkspace 429 | if(g_hycov_disable_workspace_change) { 430 | g_hycov_pChangeworkspaceHook->hook(); 431 | g_hycov_pMoveActiveToWorkspaceHook->hook(); 432 | } 433 | 434 | //disable spawn 435 | if(g_hycov_disable_spawn) { 436 | g_hycov_pSpawnHook->hook(); 437 | } 438 | 439 | g_hycov_pCKeybindManager_changeGroupActiveHook->hook(); 440 | g_hycov_pCKeybindManager_toggleGroupHook->hook(); 441 | g_hycov_pCKeybindManager_moveOutOfGroupHook->hook(); 442 | 443 | return; 444 | } 445 | 446 | void dispatch_leaveoverview(std::string arg) 447 | { 448 | if(!g_hycov_isOverView) { 449 | return; 450 | } 451 | 452 | const auto pMonitor = g_pCompositor->m_lastMonitor; 453 | if(pMonitor->activeSpecialWorkspaceID() != 0) 454 | pMonitor->setSpecialWorkspace(nullptr); 455 | 456 | // get default layout 457 | std::string *configLayoutName = &g_hycov_configLayoutName; 458 | 459 | hycov_log(LOG,"leave overview"); 460 | g_hycov_isOverView = false; 461 | //mark exiting overview mode 462 | g_hycov_isOverViewExiting = true; 463 | 464 | //restore workspace name 465 | g_pCompositor->getWorkspaceByID(workspaceIdBackup)->m_name = std::move(workspaceNameBackup); 466 | 467 | //enable changeworkspace 468 | if(g_hycov_disable_workspace_change) { 469 | g_hycov_pChangeworkspaceHook->unhook(); 470 | g_hycov_pMoveActiveToWorkspaceHook->unhook(); 471 | } 472 | 473 | //enable spawn 474 | if(g_hycov_disable_spawn) { 475 | g_hycov_pSpawnHook->unhook(); 476 | } 477 | 478 | g_hycov_pCKeybindManager_changeGroupActiveHook->unhook(); 479 | g_hycov_pCKeybindManager_toggleGroupHook->unhook(); 480 | g_hycov_pCKeybindManager_moveOutOfGroupHook->unhook(); 481 | 482 | // if no clients, just exit overview, don't restore client's state 483 | if (g_hycov_OvGridLayout->m_lOvGridNodesData.empty()) 484 | { 485 | switchToLayoutWithoutReleaseData(*configLayoutName); 486 | recalculateAllMonitor(); 487 | g_hycov_OvGridLayout->m_lOvGridNodesData.clear(); 488 | g_hycov_isOverViewExiting = false; 489 | return; 490 | } 491 | 492 | //move clients to it's original workspace 493 | g_hycov_OvGridLayout->moveWindowToSourceWorkspace(); 494 | // go to the workspace where the active client was before 495 | g_hycov_OvGridLayout->changeToActivceSourceWorkspace(); 496 | 497 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) 498 | { 499 | //make all window restore it's style 500 | // n.pWindow->m_sSpecialRenderData.border = n.ovbk_windowIsWithBorder; 501 | // n.pWindow->m_sSpecialRenderData.decorate = n.ovbk_windowIsWithDecorate; 502 | // n.pWindow->m_sSpecialRenderData.rounding = n.ovbk_windowIsWithRounding; 503 | // n.pWindow->m_sSpecialRenderData.shadow = n.ovbk_windowIsWithShadow; 504 | 505 | if (n.ovbk_windowIsFloating) 506 | { 507 | //make floating client restore it's floating status 508 | n.pWindow->m_isFloating = true; 509 | g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(n.pWindow); 510 | 511 | // make floating client restore it's position and size 512 | n.pWindow->m_realSize->value() = n.ovbk_size; 513 | n.pWindow->m_realPosition->value() = n.ovbk_position; 514 | 515 | auto calcPos = n.ovbk_position; 516 | auto calcSize = n.ovbk_size; 517 | 518 | n.pWindow->m_realSize->value() = calcSize; 519 | n.pWindow->m_realPosition->value() = calcPos; 520 | 521 | // g_pXWaylandManager->setWindowSize(n.pWindow, calcSize); 522 | 523 | } else if(!n.ovbk_windowIsFloating && !n.ovbk_windowIsFullscreen) { 524 | // make nofloating client restore it's position and size 525 | n.pWindow->m_realSize->value() = n.ovbk_size; 526 | n.pWindow->m_realPosition->value() = n.ovbk_position; 527 | 528 | // auto calcPos = n.ovbk_position; 529 | // auto calcSize = n.ovbk_size; 530 | 531 | // n.pWindow->m_vRealSize = calcSize; 532 | // n.pWindow->m_vRealPosition = calcPos; 533 | 534 | // some app sometime can't catch window size to restore,don't use dirty data,remove refer data in old layout. 535 | if (n.ovbk_size.x == 0 && n.ovbk_size.y == 0 && n.isInOldLayout) { 536 | g_hycov_OvGridLayout->removeOldLayoutData(n.pWindow); 537 | n.isInOldLayout = false; 538 | } else { 539 | // g_pXWaylandManager->setWindowSize(n.pWindow, n.ovbk_size); 540 | } 541 | 542 | // restore active window in group 543 | if(n.isGroupActive) { 544 | n.pWindow->setGroupCurrent(n.pWindow); 545 | } 546 | } 547 | } 548 | 549 | //exit overview layout,go back to old layout 550 | PHLWINDOW pActiveWindow = g_pCompositor->m_lastWindow.lock(); 551 | g_pCompositor->focusWindow(nullptr); 552 | // g_pLayoutManager->switchToLayout(*configLayoutName); 553 | // g_pLayoutManager->getCurrentLayout()->onDisable(); 554 | switchToLayoutWithoutReleaseData(*configLayoutName); 555 | recalculateAllMonitor(); 556 | 557 | //Preserve window focus 558 | if(pActiveWindow){ 559 | if(g_hycov_forece_display_all_in_one_monitor && pActiveWindow->monitorID() != g_pCompositor->m_lastMonitor->m_id) { 560 | 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 561 | } else { 562 | g_pCompositor->focusWindow(pActiveWindow); //restore the focus to before active window 563 | } 564 | 565 | if(pActiveWindow->m_isFloating && g_hycov_raise_float_to_top) { 566 | g_pCompositor->changeWindowZOrder(pActiveWindow, true); 567 | } else if(g_hycov_auto_fullscreen && want_auto_fullscren(pActiveWindow)) { // if enale auto_fullscreen after exit overview 568 | g_pCompositor->setWindowFullscreenState(pActiveWindow, { .internal = FSMODE_NONE, .client = FSMODE_MAXIMIZED }); 569 | } 570 | } 571 | 572 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) 573 | { 574 | //make all fullscrenn windwo restore it's status 575 | if (n.ovbk_windowIsFullscreen) 576 | { 577 | if (!g_pCompositor->m_lastWindow.lock()) { 578 | continue; 579 | } 580 | 581 | if (n.pWindow != g_pCompositor->m_lastWindow.lock() && n.pWindow->m_workspace == g_pCompositor->m_lastWindow.lock()->m_workspace) 582 | { 583 | continue; 584 | } 585 | g_pCompositor->setWindowFullscreenState(pActiveWindow, { .internal = FSMODE_NONE, .client = FSMODE_MAXIMIZED }); 586 | } 587 | } 588 | 589 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) 590 | { 591 | // if client not in old layout,create tiling of the client 592 | if(!n.isInOldLayout) 593 | { 594 | if (n.pWindow->m_fadingOut || !n.pWindow->m_isMapped || n.pWindow->isHidden()) { 595 | continue; 596 | } 597 | hycov_log(LOG,"create tiling window in old layout,window:{},workspace:{},inoldlayout:{}",n.pWindow,n.workspaceID,n.isInOldLayout); 598 | g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(n.pWindow); 599 | } 600 | // restore active window in group 601 | if(n.isGroupActive) { 602 | n.pWindow->setGroupCurrent(n.pWindow); 603 | } 604 | } 605 | 606 | //clean overview layout node date 607 | g_hycov_OvGridLayout->m_lOvGridNodesData.clear(); 608 | 609 | //mark has exited overview mode 610 | g_hycov_isOverViewExiting = false; 611 | 612 | // disable hook fullscreenActive funciton 613 | g_hycov_pFullscreenActiveHook->unhook(); 614 | 615 | return; 616 | } 617 | 618 | void registerDispatchers() 619 | { 620 | HyprlandAPI::addDispatcher(PHANDLE, "hycov:enteroverview", dispatch_enteroverview); 621 | HyprlandAPI::addDispatcher(PHANDLE, "hycov:leaveoverview", dispatch_leaveoverview); 622 | HyprlandAPI::addDispatcher(PHANDLE, "hycov:toggleoverview", dispatch_toggleoverview); 623 | HyprlandAPI::addDispatcher(PHANDLE, "hycov:movefocus", dispatch_focusdir); 624 | } 625 | -------------------------------------------------------------------------------- /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 | #include "src/desktop/Workspace.hpp" 9 | #include "src/helpers/Monitor.hpp" 10 | #include "src/layout/DwindleLayout.hpp" 11 | #include "src/layout/MasterLayout.hpp" 12 | #include "src/managers/input/InputManager.hpp" 13 | 14 | // std::unique_ptr mouseMoveHookPtr = std::make_unique(mouseMoveHook); 15 | // std::unique_ptr mouseButtonHookPtr = std::make_unique(mouseButtonHook); 16 | typedef void (*origCWindow_onUnmap)(void*); 17 | typedef void (*origStartAnim)(void*, bool in, bool left, bool instant); 18 | typedef void (*origFullscreenActive)(std::string args); 19 | typedef void (*origOnKeyboardKey)(void*, std::any e, SP pKeyboard); 20 | typedef void (*origCInputManager_onMouseButton)(void*, IPointer::SButtonEvent e); 21 | typedef void (*origCInputManager_mouseMoveUnified)(void* , uint32_t time, bool refocus); 22 | 23 | static double gesture_dx,gesture_previous_dx; 24 | static double gesture_dy,gesture_previous_dy; 25 | 26 | std::string getKeynameFromKeycode(IKeyboard::SKeyEvent e, SP pKeyboard) { 27 | auto keyboard = pKeyboard.get(); 28 | xkb_keycode_t keycode = e.keycode + 8; 29 | xkb_keysym_t keysym = xkb_state_key_get_one_sym(keyboard->m_xkbState, keycode); 30 | char *tmp_keyname = new char[64]; 31 | xkb_keysym_get_name(keysym, tmp_keyname, 64); 32 | std::string keyname = tmp_keyname; 33 | delete[] tmp_keyname; 34 | return keyname; 35 | } 36 | 37 | bool isKeyReleaseToggleExitOverviewHit(IKeyboard::SKeyEvent e, SP pKeyboard) { 38 | if (g_hycov_alt_replace_key == "") 39 | return false; 40 | 41 | 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)) { 42 | return true; 43 | } 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)) { 44 | return true; 45 | } else { 46 | std::string keyname = getKeynameFromKeycode(e,pKeyboard); 47 | if (keyname == g_hycov_alt_replace_key) { 48 | return true; 49 | } 50 | } 51 | 52 | return false; 53 | } 54 | 55 | static void toggle_hotarea(int x_root, int y_root) 56 | { 57 | CMonitor *pMonitor = g_pCompositor->m_lastMonitor.get(); 58 | 59 | if (g_hycov_hotarea_monitor != "all" && pMonitor->m_name!= g_hycov_hotarea_monitor) 60 | return; 61 | 62 | auto m_x = pMonitor->m_position.x; 63 | auto m_y = pMonitor->m_position.y; 64 | auto m_width = pMonitor->m_position.x; 65 | auto m_height = pMonitor->m_position.y; 66 | 67 | if (!g_hycov_isInHotArea && 68 | ((g_hycov_hotarea_pos == 1 && x_root < (m_x + g_hycov_hotarea_size) && y_root > (m_y + m_height - g_hycov_hotarea_size)) || 69 | (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)) || 70 | (g_hycov_hotarea_pos == 3 && x_root < (m_x + g_hycov_hotarea_size) && y_root < (m_y + g_hycov_hotarea_size)) || 71 | (g_hycov_hotarea_pos == 4 && x_root > (m_x + m_width - g_hycov_hotarea_size) && y_root < (m_y + g_hycov_hotarea_size)))) 72 | { 73 | g_hycov_isInHotArea = true; 74 | hycov_log(LOG,"cursor enter hotarea"); 75 | dispatch_toggleoverview("internalToggle"); 76 | } 77 | else if (g_hycov_isInHotArea && 78 | !((g_hycov_hotarea_pos == 1 && x_root < (m_x + g_hycov_hotarea_size) && y_root > (m_y + m_height - g_hycov_hotarea_size)) || 79 | (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)) || 80 | (g_hycov_hotarea_pos == 3 && x_root < (m_x + g_hycov_hotarea_size) && y_root < (m_y + g_hycov_hotarea_size)) || 81 | (g_hycov_hotarea_pos == 4 && x_root > (m_x + m_width - g_hycov_hotarea_size) && y_root < (m_y + g_hycov_hotarea_size)))) 82 | { 83 | g_hycov_isInHotArea = false; 84 | } 85 | } 86 | 87 | static void hkCInputManager_mouseMoveUnified(void* thisptr, uint32_t time, bool refocus) 88 | { 89 | (*(origCInputManager_mouseMoveUnified)g_hycov_pCInputManager_mouseMoveUnifiedHook->m_original)(thisptr, time, refocus); 90 | 91 | Vector2D mouseCoords = g_pInputManager->getMouseCoordsInternal(); 92 | const auto MOUSECOORDSFLOORED = mouseCoords.floor(); 93 | 94 | toggle_hotarea(MOUSECOORDSFLOORED.x, MOUSECOORDSFLOORED.y); 95 | } 96 | 97 | static void hkCInputManager_onMouseButton(void* thisptr, IPointer::SButtonEvent e) 98 | { 99 | if(g_hycov_isOverView && (e.button == BTN_LEFT || e.button == BTN_RIGHT) ) { 100 | 101 | if (g_hycov_click_in_cursor) { 102 | g_pInputManager->refocus(); 103 | } 104 | 105 | if (!g_pCompositor->m_lastWindow.lock()) { 106 | return; 107 | } 108 | 109 | switch (e.button) 110 | { 111 | case BTN_LEFT: 112 | if (g_hycov_isOverView && e.state == WL_POINTER_BUTTON_STATE_PRESSED) 113 | { 114 | dispatch_toggleoverview("internalToggle"); 115 | return; 116 | } 117 | break; 118 | case BTN_RIGHT: 119 | if (g_hycov_isOverView && e.state == WL_POINTER_BUTTON_STATE_PRESSED) 120 | { 121 | g_pCompositor->closeWindow(g_pCompositor->m_lastWindow.lock()); 122 | return; 123 | } 124 | break; 125 | } 126 | } else { 127 | (*(origCInputManager_onMouseButton)g_hycov_pCInputManager_onMouseButtonHook->m_original)(thisptr, e); 128 | } 129 | } 130 | 131 | 132 | static void hkCWindow_onUnmap(void* thisptr) { 133 | // call the original function,Let it do what it should do 134 | (*(origCWindow_onUnmap)g_hycov_pCWindow_onUnmap->m_original)(thisptr); 135 | 136 | // after done original thing,The workspace automatically exit overview if no client exists 137 | auto nodeNumInSameMonitor = 0; 138 | auto nodeNumInSameWorkspace = 0; 139 | for (auto &n : g_hycov_OvGridLayout->m_lOvGridNodesData) { 140 | if(n.pWindow->monitorID() == g_pCompositor->m_lastMonitor->m_id && !g_pCompositor->isWorkspaceSpecial(n.workspaceID)) { 141 | nodeNumInSameMonitor++; 142 | } 143 | if(n.pWindow->m_workspace == g_pCompositor->m_lastMonitor->m_activeWorkspace) { 144 | nodeNumInSameWorkspace++; 145 | } 146 | } 147 | 148 | if (g_hycov_isOverView && nodeNumInSameMonitor == 0) { 149 | hycov_log(LOG,"no tiling window in same monitor,auto exit overview"); 150 | dispatch_leaveoverview(""); 151 | return; 152 | } 153 | 154 | if (g_hycov_isOverView && nodeNumInSameWorkspace == 0 && (g_hycov_only_active_workspace || g_hycov_force_display_only_current_workspace)) { 155 | hycov_log(LOG,"no tiling windwo in same workspace,auto exit overview"); 156 | dispatch_leaveoverview(""); 157 | return; 158 | } 159 | 160 | } 161 | 162 | static void hkChangeworkspace(std::string args) { 163 | // just log a message and do nothing, mean the original function is disabled 164 | hycov_log(LOG,"ChangeworkspaceHook hook toggle"); 165 | } 166 | 167 | static void hkMoveActiveToWorkspace(std::string args) { 168 | // just log a message and do nothing, mean the original function is disabled 169 | hycov_log(LOG,"MoveActiveToWorkspace hook toggle"); 170 | } 171 | 172 | static void hkSpawn(std::string args) { 173 | // just log a message and do nothing, mean the original function is disabled 174 | hycov_log(LOG,"Spawn hook toggle"); 175 | } 176 | 177 | static void hkStartAnim(void* thisptr,bool in, bool left, bool instant = false) { 178 | // if is exiting overview, omit the animation of workspace change (instant = true) 179 | if (g_hycov_isOverViewExiting) { 180 | (*(origStartAnim)g_hycov_pStartAnimHook->m_original)(thisptr, in, left, true); 181 | hycov_log(LOG,"hook startAnim,disable workspace change anim,in:{},isOverview:{}",in,g_hycov_isOverView); 182 | } else { 183 | (*(origStartAnim)g_hycov_pStartAnimHook->m_original)(thisptr, in, left, instant); 184 | // hycov_log(LOG,"hook startAnim,enable workspace change anim,in:{},isOverview:{}",in,g_hycov_isOverView); 185 | } 186 | } 187 | 188 | static void hkOnKeyboardKey(void* thisptr,std::any event, SP pKeyboard) { 189 | 190 | (*(origOnKeyboardKey)g_hycov_pOnKeyboardKeyHook->m_original)(thisptr, event, pKeyboard); 191 | 192 | auto e = std::any_cast(event); 193 | // hycov_log(LOG,"alt key,keycode:{}",e.keycode); 194 | if(g_hycov_enable_alt_release_exit && g_hycov_isOverView && e.state == WL_KEYBOARD_KEY_STATE_RELEASED) { 195 | if (!isKeyReleaseToggleExitOverviewHit(e,pKeyboard)) 196 | return; 197 | dispatch_leaveoverview(""); 198 | hycov_log(LOG,"alt key release toggle leave overview"); 199 | } 200 | 201 | } 202 | 203 | static void hkFullscreenActive(std::string args) { 204 | // auto exit overview and fullscreen window when toggle fullscreen in overview mode 205 | hycov_log(LOG,"FullscreenActive hook toggle"); 206 | 207 | // (*(origFullscreenActive)g_hycov_pFullscreenActiveHook->m_original)(args); 208 | const auto pWindow = g_pCompositor->m_lastWindow.lock(); 209 | 210 | if (!pWindow) 211 | return; 212 | 213 | if (pWindow->m_workspace->m_isSpecialWorkspace) 214 | return; 215 | 216 | if (g_hycov_isOverView && want_auto_fullscren(pWindow) && !g_hycov_auto_fullscreen) { 217 | hycov_log(LOG,"FullscreenActive toggle leave overview with fullscreen"); 218 | dispatch_toggleoverview("internalToggle"); 219 | } else if (g_hycov_isOverView && (!want_auto_fullscren(pWindow) || g_hycov_auto_fullscreen)) { 220 | hycov_log(LOG,"FullscreenActive toggle leave overview without fullscreen"); 221 | dispatch_toggleoverview("internalToggle"); 222 | } else { 223 | hycov_log(LOG,"FullscreenActive set fullscreen"); 224 | g_pCompositor->setWindowFullscreenState(pWindow, {.internal =!pWindow->isFullscreen() ? FSMODE_MAXIMIZED: FSMODE_NONE,.client = args == "1" ? FSMODE_MAXIMIZED: FSMODE_FULLSCREEN}); 225 | } 226 | } 227 | 228 | void hkHyprDwindleLayout_recalculateMonitor(void* thisptr,const int& ID) { 229 | ; 230 | } 231 | 232 | void hkHyprMasterLayout_recalculateMonitor(void* thisptr,const int& ID) { 233 | ; 234 | } 235 | 236 | void hkHyprDwindleLayout_recalculateWindow(void* thisptr,CWindow* pWindow) { 237 | ; 238 | } 239 | 240 | void hkSDwindleNodeData_recalcSizePosRecursive(void* thisptr,bool force, bool horizontalOverride, bool verticalOverride) { 241 | ; 242 | } 243 | 244 | void hkCKeybindManager_toggleGroup(std::string args) { 245 | ; 246 | } 247 | 248 | void hkCKeybindManager_moveOutOfGroup(std::string args) { 249 | ; 250 | } 251 | 252 | void hkCKeybindManager_changeGroupActive(std::string args) { 253 | const auto PWINDOW = g_pCompositor->m_lastWindow.lock(); 254 | PHLWINDOW pTargetWindow; 255 | if (!PWINDOW) 256 | return; 257 | 258 | if (!PWINDOW->m_groupData.pNextWindow.lock()) 259 | return; 260 | 261 | if (PWINDOW->m_groupData.pNextWindow.lock() == PWINDOW) 262 | return; 263 | 264 | auto pNode = g_hycov_OvGridLayout->getNodeFromWindow(PWINDOW); 265 | if (!pNode) 266 | return; 267 | 268 | if (args != "b" && args != "prev") { 269 | pTargetWindow = PWINDOW->m_groupData.pNextWindow.lock(); 270 | } else { 271 | pTargetWindow = PWINDOW->getGroupPrevious(); 272 | } 273 | 274 | hycov_log(LOG,"changeGroupActive,pTargetWindow:{}",pTargetWindow); 275 | 276 | if(pNode->isInOldLayout) { // if client is taken from the old layout 277 | g_hycov_OvGridLayout->removeOldLayoutData(PWINDOW); 278 | pNode->isInOldLayout = false; 279 | } 280 | 281 | pNode->pWindow = pTargetWindow; 282 | pNode->pWindow->m_workspace = g_pCompositor->getWorkspaceByID(pNode->workspaceID); 283 | 284 | PWINDOW->setGroupCurrent(pTargetWindow); 285 | g_hycov_OvGridLayout->applyNodeDataToWindow(pNode); 286 | } 287 | 288 | 289 | void registerGlobalEventHook() 290 | { 291 | g_hycov_isInHotArea = false; 292 | g_hycov_isGestureBegin = false; 293 | g_hycov_isOverView = false; 294 | g_hycov_isOverViewExiting = false; 295 | gesture_dx = 0; 296 | gesture_dy = 0; 297 | gesture_previous_dx = 0; 298 | gesture_previous_dy = 0; 299 | 300 | // HyprlandAPI::registerCallbackStatic(PHANDLE, "mouseMove", mouseMoveHookPtr.get()); 301 | // HyprlandAPI::registerCallbackStatic(PHANDLE, "mouseButton", mouseButtonHookPtr.get()); 302 | 303 | //create public function hook 304 | 305 | // hook function of Swipe gesture event handle 306 | // hook function of Gridlayout Remove a node from tiled list 307 | g_hycov_pCWindow_onUnmap = HyprlandAPI::createFunctionHook(PHANDLE, (void *)&CWindow::onUnmap, (void*)&hkCWindow_onUnmap); 308 | 309 | // hook function of workspace change animation start 310 | g_hycov_pStartAnimHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CWorkspace::startAnim, (void*)&hkStartAnim); 311 | g_hycov_pStartAnimHook->hook(); 312 | 313 | // hook function of keypress 314 | g_hycov_pOnKeyboardKeyHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CInputManager::onKeyboardKey, (void*)&hkOnKeyboardKey); 315 | 316 | // layotu reculate 317 | g_hycov_pHyprDwindleLayout_recalculateMonitorHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CHyprDwindleLayout::recalculateMonitor, (void*)&hkHyprDwindleLayout_recalculateMonitor); 318 | g_hycov_pHyprMasterLayout_recalculateMonitorHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CHyprMasterLayout::recalculateMonitor, (void*)&hkHyprMasterLayout_recalculateMonitor); 319 | g_hycov_pHyprDwindleLayout_recalculateWindowHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CHyprDwindleLayout::recalculateWindow, (void*)&hkHyprDwindleLayout_recalculateWindow); 320 | g_hycov_pSDwindleNodeData_recalcSizePosRecursiveHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&SDwindleNodeData::recalcSizePosRecursive, (void*)&hkSDwindleNodeData_recalcSizePosRecursive); 321 | 322 | 323 | //mousebutto 324 | g_hycov_pCInputManager_onMouseButtonHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CInputManager::onMouseButton, (void*)&hkCInputManager_onMouseButton); 325 | 326 | 327 | //changeGroupActive 328 | g_hycov_pCKeybindManager_changeGroupActiveHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CKeybindManager::changeGroupActive, (void*)&hkCKeybindManager_changeGroupActive); 329 | 330 | //toggleGroup 331 | g_hycov_pCKeybindManager_toggleGroupHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CKeybindManager::toggleGroup, (void*)&hkCKeybindManager_toggleGroup); 332 | //moveOutOfGroup 333 | g_hycov_pCKeybindManager_moveOutOfGroupHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CKeybindManager::moveOutOfGroup, (void*)&hkCKeybindManager_moveOutOfGroup); 334 | //mouse 335 | // g_hycov_pCInputManager_mouseMoveUnifiedHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CInputManager::mouseMoveUnified, (void*)&hkCInputManager_mouseMoveUnified); 336 | 337 | 338 | //create private function hook 339 | 340 | // hook function of changeworkspace 341 | static const auto ChangeworkspaceMethods = HyprlandAPI::findFunctionsByName(PHANDLE, "changeworkspace"); 342 | g_hycov_pChangeworkspaceHook = HyprlandAPI::createFunctionHook(PHANDLE, ChangeworkspaceMethods[0].address, (void*)&hkChangeworkspace); 343 | 344 | // hook function of moveActiveToWorkspace 345 | static const auto MoveActiveToWorkspaceMethods = HyprlandAPI::findFunctionsByName(PHANDLE, "moveActiveToWorkspace"); 346 | g_hycov_pMoveActiveToWorkspaceHook = HyprlandAPI::createFunctionHook(PHANDLE, MoveActiveToWorkspaceMethods[0].address, (void*)&hkMoveActiveToWorkspace); 347 | 348 | // hook function of spawn (bindkey will call spawn to excute a command or a dispatch) 349 | static const auto SpawnMethods = HyprlandAPI::findFunctionsByName(PHANDLE, "spawn"); 350 | g_hycov_pSpawnHook = HyprlandAPI::createFunctionHook(PHANDLE, SpawnMethods[0].address, (void*)&hkSpawn); 351 | 352 | //hook function of fullscreenActive 353 | static const auto FullscreenActiveMethods = HyprlandAPI::findFunctionsByName(PHANDLE, "fullscreenActive"); 354 | g_hycov_pFullscreenActiveHook = HyprlandAPI::createFunctionHook(PHANDLE, FullscreenActiveMethods[0].address, (void*)&hkFullscreenActive); 355 | 356 | //register pEvent hook 357 | if(g_hycov_enable_hotarea){ 358 | // g_hycov_pCInputManager_mouseMoveUnifiedHook->hook(); 359 | // static auto mouseMoveHook = HyprlandAPI::registerCallbackDynamic(PHANDLE, "mouseMove",[&](void* self, SCallbackInfo& info, std::any data) { hkmouseMove(self, info, data); }); 360 | } 361 | 362 | if(g_hycov_enable_click_action) { 363 | g_hycov_pCInputManager_onMouseButtonHook->hook(); 364 | } 365 | 366 | //if enable gesture, apply hook Swipe function 367 | if(g_hycov_enable_gesture){ 368 | g_hycov_pOnSwipeBeginHook->hook(); 369 | g_hycov_pOnSwipeEndHook->hook(); 370 | g_hycov_pOnSwipeUpdateHook->hook(); 371 | } 372 | 373 | //if enable auto_exit, apply hook RemovedTiling function 374 | if(g_hycov_auto_exit){ 375 | g_hycov_pCWindow_onUnmap->hook(); 376 | } 377 | 378 | //apply hook OnKeyboardKey function 379 | if (g_hycov_enable_alt_release_exit) { 380 | g_hycov_pOnKeyboardKeyHook->hook(); 381 | } 382 | 383 | } 384 | -------------------------------------------------------------------------------- /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", CHyprColor(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(eLogLevel 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 | #include "src/config/ConfigManager.hpp" 6 | 7 | APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; } 8 | 9 | APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) 10 | { 11 | PHANDLE = handle; 12 | 13 | #define CONF(NAME,VALUE) \ 14 | HyprlandAPI::addConfigValue(PHANDLE, "plugin:hycov:" NAME, {VALUE}) 15 | 16 | CONF("overview_gappo", 60L); 17 | CONF("overview_gappi", 24L); 18 | CONF("hotarea_size", 10L); 19 | CONF("hotarea_pos", 1L); 20 | CONF("enable_hotarea", 1L); 21 | CONF("swipe_fingers", 4L); 22 | CONF("move_focus_distance", 100L); 23 | CONF("enable_gesture", 0L); 24 | CONF("disable_workspace_change", 1L); 25 | CONF("disable_spawn", 0L); 26 | CONF("auto_exit", 1L); 27 | CONF("auto_fullscreen", 0L); 28 | CONF("only_active_workspace", 0L); 29 | CONF("only_active_monitor", 0L); 30 | CONF("enable_alt_release_exit", 0L); 31 | CONF("alt_toggle_auto_next", 0L); 32 | CONF("click_in_cursor", 1L); 33 | CONF("height_of_titlebar", 0L); 34 | CONF("hotarea_monitor", "all"); 35 | CONF("alt_replace_key", "Alt_L"); 36 | CONF("show_special", 0L); 37 | CONF("enable_click_action", 1L); 38 | CONF("raise_float_to_top", 1L); 39 | 40 | #undef CONF 41 | 42 | HyprlandAPI::reloadConfig(); 43 | g_pConfigManager->reload(); 44 | 45 | // int value 46 | static const auto *pEnable_hotarea_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:enable_hotarea")->getDataStaticPtr()); 47 | static const auto *pHotarea_pos_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:hotarea_pos")->getDataStaticPtr()); 48 | static const auto *pHotarea_size_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:hotarea_size")->getDataStaticPtr()); 49 | static const auto *pSwipe_fingers_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:swipe_fingers")->getDataStaticPtr()); 50 | static const auto *pMove_focus_distance_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:move_focus_distance")->getDataStaticPtr()); 51 | static const auto *pEnable_gesture_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:enable_gesture")->getDataStaticPtr()); 52 | static const auto *pDisable_workspace_change_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:disable_workspace_change")->getDataStaticPtr()); 53 | static const auto *pDisable_spawn_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:disable_spawn")->getDataStaticPtr()); 54 | static const auto *pAuto_exit_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:auto_exit")->getDataStaticPtr()); 55 | static const auto *pAuto_fullscreen = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:auto_fullscreen")->getDataStaticPtr()); 56 | static const auto *pOnly_active_workspace = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:only_active_workspace")->getDataStaticPtr()); 57 | static const auto *pOnly_active_monitor = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:only_active_monitor")->getDataStaticPtr()); 58 | static const auto *pEnable_alt_release_exit = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:enable_alt_release_exit")->getDataStaticPtr()); 59 | static const auto *pAlt_toggle_auto_next = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:alt_toggle_auto_next")->getDataStaticPtr()); 60 | static const auto *pClick_in_cursor = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:click_in_cursor")->getDataStaticPtr()); 61 | static const auto *pHeight_of_titlebar = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:height_of_titlebar")->getDataStaticPtr()); 62 | static const auto *pBordersize = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->getDataStaticPtr()); 63 | static const auto *pOverview_gappo = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:overview_gappo")->getDataStaticPtr()); 64 | static const auto *pOverview_gappi = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:overview_gappi")->getDataStaticPtr()); 65 | static const auto *pShow_special_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:show_special")->getDataStaticPtr()); 66 | static const auto *pEnable_click_action_config = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:enable_click_action")->getDataStaticPtr()); 67 | static const auto *pRaise_float_to_top = (Hyprlang::INT* const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:raise_float_to_top")->getDataStaticPtr()); 68 | 69 | 70 | // string value 71 | static const auto *pAlt_replace_key = (Hyprlang::STRING const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:alt_replace_key")->getDataStaticPtr()); 72 | static const auto *pHotarea_monitor_config = (Hyprlang::STRING const*)(HyprlandAPI::getConfigValue(PHANDLE, "plugin:hycov:hotarea_monitor")->getDataStaticPtr()); 73 | static const auto *pConfigLayoutName = (Hyprlang::STRING const*)(HyprlandAPI::getConfigValue(PHANDLE, "general:layout")->getDataStaticPtr()); 74 | static const auto *pGroupBarHeight = (Hyprlang::STRING const*)(HyprlandAPI::getConfigValue(PHANDLE, "group:groupbar:height")->getDataStaticPtr()); 75 | 76 | 77 | // int value 78 | g_hycov_enable_hotarea = **pEnable_hotarea_config; 79 | g_hycov_hotarea_pos = **pHotarea_pos_config; 80 | g_hycov_hotarea_size = **pHotarea_size_config; 81 | g_hycov_swipe_fingers = **pSwipe_fingers_config; 82 | g_hycov_move_focus_distance = **pMove_focus_distance_config; 83 | g_hycov_enable_gesture = **pEnable_gesture_config; 84 | g_hycov_disable_workspace_change = **pDisable_workspace_change_config; 85 | g_hycov_disable_spawn = **pDisable_spawn_config; 86 | g_hycov_auto_exit = **pAuto_exit_config; 87 | g_hycov_auto_fullscreen = **pAuto_fullscreen; 88 | g_hycov_only_active_workspace = **pOnly_active_workspace; 89 | g_hycov_only_active_monitor = **pOnly_active_monitor; 90 | g_hycov_enable_alt_release_exit = **pEnable_alt_release_exit; 91 | g_hycov_alt_toggle_auto_next = **pAlt_toggle_auto_next; 92 | g_hycov_click_in_cursor = **pClick_in_cursor; 93 | g_hycov_height_of_titlebar= **pHeight_of_titlebar; 94 | g_hycov_bordersize = **pBordersize; 95 | g_hycov_overview_gappo = **pOverview_gappo; 96 | g_hycov_overview_gappi = **pOverview_gappi; 97 | g_hycov_show_special = **pShow_special_config; 98 | g_hycov_enable_click_action = **pEnable_click_action_config; 99 | g_hycov_raise_float_to_top = **pRaise_float_to_top; 100 | 101 | 102 | // string value 103 | g_hycov_alt_replace_key = *pAlt_replace_key; 104 | g_hycov_hotarea_monitor = *pHotarea_monitor_config; 105 | g_hycov_configLayoutName = *pConfigLayoutName; 106 | 107 | g_hycov_groupBarHeight= **pGroupBarHeight; 108 | 109 | 110 | g_hycov_OvGridLayout = std::make_unique(); 111 | HyprlandAPI::addLayout(PHANDLE, "ovgrid", g_hycov_OvGridLayout.get()); 112 | 113 | registerGlobalEventHook(); 114 | registerDispatchers(); 115 | 116 | HyprlandAPI::reloadConfig(); 117 | return {"hycov", "overview mode", "DreamMaoMao", "0.3"}; 118 | } 119 | 120 | APICALL EXPORT void PLUGIN_EXIT() {} 121 | --------------------------------------------------------------------------------