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