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