Compare commits

...

179 Commits

Author SHA1 Message Date
vaxerski
61aa4ff70e [gha] bump flake inputs 2022-08-20 18:07:29 +00:00
vaxerski
cc3f0ff9e7 update wlroots dep 2022-08-20 20:06:24 +02:00
vaxerski
7af193d921 reload on input and device hyprctl 2022-08-20 18:57:30 +02:00
vaxerski
132c96f867 multiple fixes for device configs 2022-08-20 18:47:48 +02:00
vaxerski
45a0e69286 Find a candidate better on window close 2022-08-20 18:12:59 +02:00
vaxerski
0ebef9a8ae no focus to OR Xwayland 2022-08-20 18:00:50 +02:00
vaxerski
185f93ae64 fix dwindle active for splits 2022-08-20 17:59:15 +02:00
vaxerski
1b1a0259a8 fix crash 2022-08-19 23:22:59 +02:00
Vaxry
223ca6e286 Merge pull request #548 from FlafyDev/main
add input:kb_file option to use a .xkb file.
2022-08-19 22:39:50 +02:00
FlafyDev
f0ad77251b move absolutePath to MiscFunctions 2022-08-19 23:18:09 +03:00
vaxerski
c2a3896cc9 added dwindle:use_active_for_splits 2022-08-19 22:03:41 +02:00
Vaxry
e749331f30 update wiki links in readme 2022-08-19 21:50:57 +02:00
FlafyDev
69d17bf424 add input:kb_file 2022-08-19 21:01:51 +03:00
vaxerski
946222f4a7 fix typo in swipe alpha control 2022-08-19 17:42:10 +02:00
vaxerski
504d07a87d fix swipe on workspace style fade 2022-08-19 17:36:01 +02:00
vaxerski
81b27be6bb reset lastwindow on full LS focus 2022-08-19 17:29:16 +02:00
vaxerski
f9e30e985c fix refocus on no window 2022-08-19 17:25:07 +02:00
vaxerski
6cae44e2c0 fix custom rounding in shadow deco 2022-08-19 14:52:18 +02:00
vaxerski
43aea417b0 Fix occasional hangups on exit 2022-08-18 22:36:58 +02:00
Vaxry
ece3ac97f9 Merge pull request #543 from Roger-Roger-debug/main
More fullscreen animation fixes
2022-08-18 19:51:37 +02:00
vaxerski
9b62328b22 minor changes to the activelayout event 2022-08-18 17:50:32 +02:00
vaxerski
c1a64a2b9d added main param to keyboards 2022-08-18 17:34:01 +02:00
vaxerski
b078a12eed Added an activelayout event 2022-08-18 17:17:33 +02:00
Roger Roger
eca6e53bd7 Animate workspaces with fullscreen windows 2022-08-18 12:42:21 +02:00
Roger Roger
f2d3aecf00 Don't draw fullscreen windows on other monitors 2022-08-18 12:41:10 +02:00
vaxerski
f3c597bfb7 fix crash 2022-08-18 07:28:07 +02:00
vaxerski
c5a4c83f78 better integrate touch with subsurfaces 2022-08-17 23:23:36 +02:00
vaxerski
f4d11d2d43 fix lastFocus on activateWindow 2022-08-17 22:59:40 +02:00
Vaxry
4c1dba643e Merge pull request #535 from Roger-Roger-debug/main
Fix workspace animation showing on other monitors
2022-08-17 12:35:03 +02:00
Roger Roger
5a20573e91 Fix workspace animation showing on other monitors 2022-08-17 12:12:16 +02:00
vaxerski
cd9c85a150 never animate moving floating windows 2022-08-16 22:40:16 +02:00
vaxerski
bbc6b5d5e0 added misc:animate_manual_resizes 2022-08-16 21:56:54 +02:00
vaxerski
a59641096c ignore dwindle reload on full window null 2022-08-16 21:32:12 +02:00
vaxerski
c6de4ee4b7 more checks in fullscreen event 2022-08-16 21:30:53 +02:00
vaxerski
317b6c430c damage monitor on workspace swipe end 2022-08-16 16:34:36 +02:00
vaxerski
095487ea5d disallow configure from fullscreen 2022-08-16 16:31:44 +02:00
vaxerski
daeb0d3418 force sending size on setWindowFullscreen 2022-08-16 16:30:10 +02:00
vaxerski
7cde50a018 scale hyprerror with the monitor res 2022-08-16 16:25:53 +02:00
vaxerski
bec7501365 fix borders on no_gaps_when_only 2022-08-16 16:19:52 +02:00
vaxerski
ea45c6bfe0 fix memory issue with hyprctl devices 2022-08-16 16:15:43 +02:00
vaxerski
6e2467cc24 fix active keymap in hyprctl devices 2022-08-16 16:10:20 +02:00
vaxerski
454d0d3f9f fix autogen config warning 2022-08-16 15:59:18 +02:00
vaxerski
d2011a4ba9 added support for window selection in moving to workspace 2022-08-15 16:12:53 +02:00
vaxerski
b0b3a5af10 added resizewindowpixel and movewindowpixel 2022-08-15 15:59:07 +02:00
vaxerski
d47bfe6af1 remove unused fixXWaylandWindowsOnWorkspace 2022-08-15 00:34:39 +02:00
Mihai Fufezan
c982312c07 Nix HM module: reload config-only 2022-08-15 00:47:56 +03:00
vaxerski
f0fe0c25d6 added config-only to hyprctl reload 2022-08-14 23:26:18 +02:00
vaxerski
d906617fb6 clean up fullscreen logic in fullscreenWindow event 2022-08-14 23:03:50 +02:00
Mihai Fufezan
ed1b72f37d Nix HM module: add XDG_SESSION_TYPE, fix reload 2022-08-14 23:45:55 +03:00
vaxerski
28867758c4 better fix the last fix 2022-08-14 16:39:56 +02:00
vaxerski
920727cbba fix crash with fullscreen requests 2022-08-14 16:34:40 +02:00
vaxerski
bfe0f844d2 fix wallpaper pixelation in some cases 2022-08-13 22:33:51 +02:00
vaxerski
214c2c7b1c fix groups not updating size on head change 2022-08-13 10:08:35 +02:00
vaxerski
9136783e9c default hardcoded rule to preferred auto 2022-08-12 22:26:35 +02:00
Vaxry
662b6003c6 Merge pull request #515 from SignalWalker/main
fix: support clang in meson build
2022-08-12 22:15:32 +02:00
Fernando Ayats
c136078239 nix: use cleanSource (#518) 2022-08-12 23:12:24 +03:00
Ash Walker
38056c0102 fix: support clang in meson build 2022-08-12 11:21:19 -04:00
vaxerski
db35a1c6d0 ensure egl is current in begin 2022-08-12 17:10:07 +02:00
vaxerski
66b0622bc5 fixed popup unmap damage 2022-08-12 17:04:26 +02:00
vaxerski
0e57651e2f fix segfault with cyclenext null 2022-08-11 22:56:16 +02:00
vaxerski
e5ab9643be enable layers_hog_keyboard_focus by default 2022-08-11 21:52:38 +02:00
vaxerski
b3c5809986 fix flags syntax in json 2022-08-11 21:29:31 +02:00
vaxerski
ae175fdda5 handle json for hyprctl version 2022-08-11 21:28:37 +02:00
vaxerski
9102471610 added hyprctl getoption 2022-08-11 21:16:38 +02:00
vaxerski
f85c765634 change activemon to focusedmon for consistency 2022-08-11 20:55:39 +02:00
vaxerski
37442db20e destroy program in shader destructor 2022-08-11 20:33:35 +02:00
vaxerski
b178891ab3 compile shaders for every context separately 2022-08-11 20:29:21 +02:00
vaxerski
073f08301a fix formatting in focused monitor hyprctl 2022-08-11 20:22:41 +02:00
vaxerski
8fb4669b85 fix cyclenext on fullscreen 2022-08-11 20:21:55 +02:00
vaxerski
008cc63dc0 fix error for popin 2022-08-11 20:17:23 +02:00
vaxerski
aba63a7f96 disallow nested groups creation 2022-08-11 19:56:29 +02:00
vaxerski
c9ed5bf77e fix cyclenext with fullscreen windows 2022-08-11 19:45:37 +02:00
vaxerski
f4f0495050 disable focus to menu x11 types 2022-08-11 19:36:15 +02:00
vaxerski
c319a2aba9 Completely rewrote Dwindle group code 2022-08-11 19:29:39 +02:00
vaxerski
cd75606f42 change active to focused in hyprctl monitors 2022-08-10 23:49:20 +02:00
vaxerski
c7350117f1 reinit render on disconnected displays 2022-08-10 23:19:15 +02:00
vaxerski
69db6207c0 don't damage in unsafe state 2022-08-10 23:14:53 +02:00
vaxerski
58ff04fdf3 added experimental monitor saving 2022-08-10 21:54:09 +02:00
vaxerski
9b39a0c2e0 Added hyprctl setcursor 2022-08-10 21:22:11 +02:00
vaxerski
f64f94ca56 scale rounding in shadows 2022-08-10 18:29:37 +02:00
vaxerski
76877d4b15 minor changes to monitor logging 2022-08-10 18:27:57 +02:00
vaxerski
96f3b62429 multiply by scale in rounding 2022-08-10 18:22:01 +02:00
vaxerski
0162da7a7c adjust curve size for scaled 2022-08-10 18:10:38 +02:00
vaxerski
9eb750c00b added misc:layers_hog_keyboard_focus 2022-08-10 17:46:01 +02:00
vaxerski
03f2e4d42a fix compile 2022-08-10 13:45:20 +02:00
vaxerski
15fc0892c7 further fixes to monitor disabling on launch 2022-08-10 13:44:04 +02:00
vaxerski
a564be73c5 set correct full params in disabled at launch 2022-08-10 13:31:58 +02:00
vaxerski
7e8666754f allow focus to override redirect 2022-08-10 12:49:45 +02:00
vaxerski
c043bcdee6 fixes to toplevel updates 2022-08-10 08:51:59 +02:00
vaxerski
8e5985d70e clean up unconstraining logic 2022-08-09 20:36:21 +02:00
vaxerski
9255a4d2ff ignore further keybinds on submap change 2022-08-09 19:54:06 +02:00
vaxerski
113ac67a16 focus monitor on monitor rule 2022-08-09 18:51:26 +02:00
vaxerski
862722412f handle fullscreen in dwindle groups better 2022-08-09 18:37:50 +02:00
vaxerski
a6d4a4d5f3 warn about incorrect bezier args 2022-08-09 18:15:37 +02:00
vaxerski
e2f61e267e add parse errors for invalid kb layouts 2022-08-09 18:13:13 +02:00
Mihai Fufezan
ecce027c02 flake: add aarch64-linux as supported platform 2022-08-09 13:17:47 +03:00
Mihai Fufezan
f28b71232a unhide window on requested size change 2022-08-09 11:57:09 +03:00
Yavor Kolev
af9d34ab77 Fix my idiotic mistake (#502)
When resolving conflicts i accepted the old changes 👨🏻🔫
2022-08-09 02:22:55 +03:00
Mihai Fufezan
2d33d4aebc nix & meson: update version to 0.10.0 2022-08-09 01:35:05 +03:00
Vaxry
aa39653ea1 Merge pull request #500 from yavko/fix-active-window-json-bools
Fix the fix
2022-08-08 22:58:34 +02:00
Yavor Kolev
6d788f0fc9 Merge branch 'main' into fix-active-window-json-bools 2022-08-08 13:51:08 -07:00
vaxerski
ab6a62f0fd Revert "Merge pull request #499 from yavko/fix-active-window-json-bools"
This reverts commit 5aed6f1bc7, reversing
changes made to 6f137938da.
2022-08-08 22:49:02 +02:00
Yavor Kolev
d460519c30 Fix the fix 2022-08-08 13:48:33 -07:00
vaxerski
b60b52c5cf fix movefocusto with null last 2022-08-08 22:46:11 +02:00
Vaxry
5aed6f1bc7 Merge pull request #499 from yavko/fix-active-window-json-bools
makes active windoe consistient with client json
2022-08-08 22:42:09 +02:00
Yavor Kolev
5cec6257e9 The fix 2022-08-08 13:39:02 -07:00
vaxerski
6f137938da send enter and leave events for surfaces 2022-08-08 21:20:41 +02:00
vaxerski
9fca4b5bc2 fix lastwindow in focusWindow null 2022-08-08 20:42:14 +02:00
vaxerski
87a2ecb90e notify of all mods in pass 2022-08-08 20:31:48 +02:00
vaxerski
bf9d358d3b fix refocus shenanigans with window data 2022-08-08 20:21:11 +02:00
vaxerski
9532ff4287 fix unconstrain coords 2022-08-07 21:27:30 +02:00
vaxerski
d64227e7c7 added basic touch controls 2022-08-07 21:17:03 +02:00
vaxerski
3a8dcf284a add more errors 2022-08-07 19:28:46 +02:00
vaxerski
1744be7bdd log more in output cfg 2022-08-07 19:28:31 +02:00
Vaxry
9fcfaaadb6 Merge pull request #484 from rubyist/unlock-then-sleep
unlock the event queue before sleeping
2022-08-06 23:32:05 +02:00
Scott Barron
355ee15039 unlock the event queue before sleeping 2022-08-06 17:21:54 -04:00
vaxerski
9564a4cd12 added misc:always_follow_on_dnd 2022-08-06 22:26:32 +02:00
vaxerski
64e80991ca added popin anim minimum % 2022-08-06 22:11:08 +02:00
Vaxry
3829b1626e Merge pull request #483 from rubyist/json-when-no-activewindow
Have hyprctl -j activewindows return empty json object if there are no activewindows
2022-08-06 21:56:16 +02:00
Scott Barron
5ce7c71cef use empty json object when no activewindow 2022-08-06 15:36:28 -04:00
vaxerski
793b23dbe6 fix crash in toplevel set appid 2022-08-06 21:15:50 +02:00
vaxerski
070db65a24 [gha] bump flake inputs 2022-08-06 19:11:51 +00:00
vaxerski
6aa448534f guard toplevel funcs 2022-08-06 21:10:37 +02:00
vaxerski
6357a92e46 update wlroots dep 2022-08-06 21:07:32 +02:00
vaxerski
68fd97fae9 change workspace in focusWindow if necessary 2022-08-06 21:05:19 +02:00
vaxerski
1b109d9242 [gha] bump flake inputs 2022-08-06 18:58:50 +00:00
vaxerski
69b8568ccf better foreign toplevel protocol obedience 2022-08-06 20:57:38 +02:00
Vaxry
ccd68049f7 Merge pull request #479 from rubyist/fix-json
output valid json when there are no clients
2022-08-06 01:06:21 +02:00
Scott Barron
206b7f4372 output valid json when there are no clients 2022-08-05 18:53:19 -04:00
Vaxry
aa7177a9e4 Merge pull request #478 from yavko/change-to-json-bools
Change more to json bools
2022-08-06 00:33:33 +02:00
yavko
59088decd0 Change to json bools 2022-08-05 15:23:38 -07:00
Vaxry
c77b571fa7 Merge pull request #474 from yavko/patch-1
Change monitor active to json bool
2022-08-05 23:54:33 +02:00
Vaxry
49f5ae2ef3 Updated the readme header 2022-08-05 22:54:27 +02:00
vaxerski
74cbfdcda4 guard zero border 2022-08-05 22:21:14 +02:00
vaxerski
f66365d9da fix crash in dwindle on create tiled 2022-08-05 20:00:17 +02:00
vaxerski
b30bb22bb8 fix crash in getMaxSizeForWindow 2022-08-05 19:41:50 +02:00
vaxerski
d72f1cc644 fix various shadow damage issues 2022-08-05 19:23:53 +02:00
vaxerski
78e4f274bc remove some spammy logs from IME 2022-08-05 19:03:03 +02:00
vaxerski
14026d4484 move IME panel below the cursor to not obstruct 2022-08-05 18:54:59 +02:00
Vaxry
f44af0366f mention IME in the readme 2022-08-05 18:52:55 +02:00
vaxerski
cd37a1533e reject tiling windows that do not meet the max size requirement 2022-08-05 18:10:59 +02:00
vaxerski
575434f1a4 fix rounding on switching only tiled 2022-08-05 18:08:23 +02:00
vaxerski
97e82fa4fb clamp resizing tiled to their max sizes 2022-08-05 17:58:08 +02:00
vaxerski
4ea37fe64d remember floating size between tiles 2022-08-05 17:52:14 +02:00
vaxerski
ad42392856 fix rare IME crash 2022-08-05 17:19:49 +02:00
vaxerski
e0ada97a24 support zwp_input_method_v2 popups 2022-08-05 17:07:01 +02:00
vaxerski
9a8a6317ff multiple IME fixes 2022-08-05 16:21:08 +02:00
vaxerski
cb5521ec6e fix possible crashes with IME 2022-08-05 13:19:16 +02:00
vaxerski
1c4d0e8c18 added IME protocol support 2022-08-05 13:03:37 +02:00
Yavor Kolev
9f11765707 Change monitor active to json bool 2022-08-04 16:25:56 -07:00
vaxerski
3947fe9e9f simplify border rendering when rounding is 0 2022-08-04 17:21:01 +02:00
vaxerski
c7c0149c08 [gha] bump flake inputs 2022-08-04 14:02:25 +00:00
vaxerski
d58233d08b update wlroots dep 2022-08-04 16:01:11 +02:00
vaxerski
07f68bf72a scale shadows properly 2022-08-04 11:18:33 +02:00
vaxerski
5e97fe8fcd use auto in default configs 2022-08-04 11:11:21 +02:00
vaxerski
81308a9cc3 add position auto for mon config 2022-08-04 11:10:26 +02:00
vaxerski
5dcbce550f only ensure DPMS in hyprctl monitors 2022-08-03 21:19:12 +02:00
vaxerski
5a96142cf8 guard monitor settings 2022-08-03 21:06:51 +02:00
vaxerski
9540106959 check for x11type and not nofocus in wcf 2022-08-03 21:03:08 +02:00
vaxerski
69558acb2e noInitialFocus in onWindowCreatedFloating as a check 2022-08-03 20:15:39 +02:00
vaxerski
37068cf4f0 fix crash with reenabling a monitor 2022-08-03 17:42:19 +02:00
vaxerski
587330d864 fix recursion bomb 2022-08-03 17:32:12 +02:00
vaxerski
9991db159c fix dynamic reenabling of a monitor 2022-08-03 17:29:05 +02:00
vaxerski
f488ec166d fix crash 2022-08-03 17:19:32 +02:00
vaxerski
871c81ac1a erase instead of overwriting monitor rules 2022-08-03 17:15:45 +02:00
vaxerski
36e563c79c reload monitors instantly on tickHyprCtl 2022-08-03 17:12:38 +02:00
vaxerski
69365c7609 fix monitor rule possible segv 2022-08-03 16:20:33 +02:00
vaxerski
c3edb20e04 make monitor IDs permanent 2022-08-03 16:19:00 +02:00
vaxerski
b9be405d32 clear ls lists on monitor disconnect 2022-08-03 16:12:05 +02:00
vaxerski
8dd88d901d guard onDisconnect 2022-08-03 16:05:25 +02:00
vaxerski
996e5a9e69 disallow swapping in fullscreen 2022-08-03 15:35:28 +02:00
vaxerski
fff7534721 fullscreen new window on fullscreen movefocus 2022-08-03 15:33:55 +02:00
vaxerski
cd483a7a37 ignore borders in nogapswhenonly 2022-08-03 15:25:30 +02:00
vaxerski
e13f2480ff fixed missing recursion of force in dwindle 2022-08-03 12:30:28 +02:00
vaxerski
f36cd350cc do not animate mouse resizes in layouts 2022-08-03 12:27:20 +02:00
vaxerski
c779a7c03b move refocus on only unmap 2022-08-03 12:03:18 +02:00
vaxerski
179e5188a4 remove incorrect border thickness calc 2022-08-03 12:03:15 +02:00
Vaxry
d3c96c248c Merge pull request #463 from luxus/patch-1
update flake to 0.9.1
2022-08-02 23:20:58 +02:00
Kai
3fabf1c483 update flake to 0.9.1
and again :D
2022-08-02 22:40:37 +02:00
56 changed files with 2595 additions and 770 deletions

View File

@@ -17,9 +17,7 @@
Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks.
For Hyprland without the `land` part, see [Hypr], the Xorg window manager.
Please note, especially for folks moving from Hypr, that Hyprland and Hypr share a very different feature set and are not 1:1 experiences.
It supports multiple layouts, fancy effects, has a very flexible IPC model allowing for a lot of customization, and more.
<br>
<br>
@@ -70,6 +68,7 @@ Try it out and report bugs / suggestions!
- Full damage tracking
- Docks support
- Drawing tablet support
- Native IME + Input panels support
- and much more...
<br>
@@ -124,7 +123,7 @@ Try it out and report bugs / suggestions!
<!----------------------------------------------------------------------------->
[Configure]: https://github.com/hyprwm/Hyprland/wiki/Configuring-Hyprland
[Configure]: https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
[Discord]: https://discord.gg/hQ9XvMUjjr
[Stars]: https://starchart.cc/hyprwm/Hyprland
[Hypr]: https://github.com/hyprwm/Hypr
@@ -133,9 +132,9 @@ Try it out and report bugs / suggestions!
[Issues]: https://github.com/hyprwm/Hyprland/issues
[Todo]: https://github.com/hyprwm/Hyprland/projects?type=beta
[Contribute]: https://github.com/hyprwm/Hyprland/wiki/Contributing-&-Debugging
[Install]: https://github.com/hyprwm/Hyprland/wiki/Installation
[Quick Start]: https://github.com/hyprwm/Hyprland/wiki/Quick-start
[Contribute]: https://wiki.hyprland.org/Contributing-and-Debugging/
[Install]: https://wiki.hyprland.org/Getting-Started/Installation/
[Quick Start]: https://wiki.hyprland.org/Getting-Started/Quick-start/
[License]: LICENSE

View File

@@ -8,10 +8,11 @@
# For a full list, see the wiki (basic and advanced configuring)
#
monitor=,preferred,0x0,1
monitor=,preferred,auto,1
workspace=DP-1,1
input {
kb_file=
kb_layout=
kb_variant=
kb_model=
@@ -112,4 +113,4 @@ bind=ALT,9,movetoworkspace,9
bind=ALT,0,movetoworkspace,10
bind=SUPER,mouse_down,workspace,e+1
bind=SUPER,mouse_up,workspace,e-1
bind=SUPER,mouse_up,workspace,e-1

12
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1659219666,
"narHash": "sha256-pzYr5fokQPHv7CmUXioOhhzDy/XyWOIXP4LZvv/T7Mk=",
"lastModified": 1660908602,
"narHash": "sha256-SwZ85IPWvC4NxxFhWhRMTJpApSHbY1u4YK2UFWEBWvY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7b9be38c7250b22d829ab6effdee90d5e40c6e5c",
"rev": "495b19d5b3e62b4ec7e846bdfb6ef3d9c3b83492",
"type": "github"
},
"original": {
@@ -26,11 +26,11 @@
"flake": false,
"locked": {
"host": "gitlab.freedesktop.org",
"lastModified": 1658770113,
"narHash": "sha256-VBq9vw0hvQPKGKLNKLJS8xsUHvrX0o2LUDBVolixenE=",
"lastModified": 1660930713,
"narHash": "sha256-bY7q1NqG/sjCUAWPn/Ne9NCigLlPlH5Lk1WCMqv3rTU=",
"owner": "wlroots",
"repo": "wlroots",
"rev": "7b5e890e61a27375725068a7d1884b26851b3102",
"rev": "7c575922c05e4d5fd9a403c2aa631a54c7531d44",
"type": "gitlab"
},
"original": {

View File

@@ -17,6 +17,7 @@
inherit (nixpkgs) lib;
genSystems = lib.genAttrs [
# Add more systems if they are supported
"aarch64-linux"
"x86_64-linux"
];
pkgsFor = nixpkgs.legacyPackages;
@@ -33,7 +34,7 @@
});
hyprland = prev.callPackage ./nix/default.nix {
stdenv = prev.gcc12Stdenv;
version = "0.9.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101"));
version = "0.10.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101"));
wlroots = wlroots-hyprland;
};
hyprland-debug = hyprland.override {debug = true;};

View File

@@ -34,6 +34,8 @@ commands:
splash
hyprpaper
reload
setcursor
getoption
flags:
-j -> output in JSON
@@ -183,6 +185,17 @@ void hyprpaperRequest(int argc, char** argv) {
requestHyprpaper(rq);
}
void setcursorRequest(int argc, char** argv) {
if (argc < 4) {
std::cout << "setcursor requires 2 params";
return;
}
std::string rq = "setcursor " + std::string(argv[2]) + " " + std::string(argv[3]);
request(rq);
}
void batchRequest(std::string arg) {
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
@@ -252,6 +265,8 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/splash")) request(fullRequest);
else if (fullRequest.contains("/devices")) request(fullRequest);
else if (fullRequest.contains("/reload")) request(fullRequest);
else if (fullRequest.contains("/getoption")) request(fullRequest);
else if (fullRequest.contains("/setcursor")) setcursorRequest(argc, argv);
else if (fullRequest.contains("/dispatch")) dispatchRequest(argc, argv);
else if (fullRequest.contains("/keyword")) keywordRequest(argc, argv);
else if (fullRequest.contains("/hyprpaper")) hyprpaperRequest(argc, argv);

View File

@@ -1,8 +1,22 @@
project('Hyprland', 'cpp', 'c',
version : '0.8.1beta',
default_options : ['warning_level=2', 'default_library=static', 'optimization=3'])
version : '0.10.0beta',
default_options : [
'warning_level=2',
'default_library=static',
'optimization=3',
# 'cpp_std=c++23' # not yet supported by meson, as of version 0.63.0
])
add_global_arguments('-std=c++23', language: 'cpp')
# clang v14.0.6 uses C++2b instead of C++23, so we've gotta account for that
# replace the following with a project default option once meson gets support for C++23
cpp_compiler = meson.get_compiler('cpp')
if cpp_compiler.has_argument('-std=c++23')
add_global_arguments('-std=c++23', language: 'cpp')
elif cpp_compiler.has_argument('-std=c++2b')
add_global_arguments('-std=c++2b', language: 'cpp')
else
error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.get_version() + ') with required C++ standard (C++23)')
endif
GIT_BRANCH = run_command('git', 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip()
GIT_COMMIT_HASH = run_command('git', 'rev-parse', 'HEAD', check: false).stdout().strip()

View File

@@ -27,7 +27,16 @@
stdenv.mkDerivation {
pname = "hyprland" + lib.optionalString debug "-debug";
inherit version;
src = ../.;
src = lib.cleanSourceWith {
filter = name: type: let
baseName = baseNameOf (toString name);
in
! (
lib.hasSuffix ".nix" baseName
);
src = lib.cleanSource ../.;
};
nativeBuildInputs = [
meson
@@ -59,7 +68,7 @@ stdenv.mkDerivation {
mesonFlags = builtins.concatLists [
(lib.optional (!enableXWayland) "-DNO_XWAYLAND=true")
(lib.optional (legacyRenderer) "-DLEGACY_RENDERER:STRING=true")
(lib.optional legacyRenderer "-DLEGACY_RENDERER:STRING=true")
];
patches = [

View File

@@ -65,9 +65,11 @@ in {
xdg.configFile."hypr/hyprland.conf" = {
text =
(lib.optionalString cfg.systemdIntegration "
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP; systemctl --user start hyprland-session.target
")
(lib.optionalString cfg.systemdIntegration ''
exec-once=export XDG_SESSION_TYPE=wayland
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP
exec-once=systemctl --user start hyprland-session.target
'')
+ cfg.extraConfig;
onChange = let
@@ -75,7 +77,7 @@ in {
if cfg.package == null
then defaultHyprlandPackage
else cfg.package;
in "${hyprlandPackage}/bin/hyprctl reload";
in "HYPRLAND_INSTANCE_SIGNATURE=$(ls -w 1 /tmp/hypr | tail -1) ${hyprlandPackage}/bin/hyprctl reload config-only";
};
systemd.user.targets.hyprland-session = lib.mkIf cfg.systemdIntegration {

View File

@@ -153,6 +153,10 @@ CCompositor::CCompositor() {
m_sWLRPointerGestures = wlr_pointer_gestures_v1_create(m_sWLDisplay);
m_sWLRSession = wlr_backend_get_session(m_sWLRBackend);
m_sWLRTextInputMgr = wlr_text_input_manager_v3_create(m_sWLDisplay);
m_sWLRIMEMgr = wlr_input_method_manager_v2_create(m_sWLDisplay);
}
CCompositor::~CCompositor() {
@@ -181,6 +185,9 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRCursor->events.pinch_begin, &Events::listen_pinchBegin, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.pinch_update, &Events::listen_pinchUpdate, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.pinch_end, &Events::listen_pinchEnd, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.touch_down, &Events::listen_touchBegin, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.touch_up, &Events::listen_touchEnd, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.touch_motion, &Events::listen_touchUpdate, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend");
addWLSignal(&m_sSeat.seat->events.request_set_cursor, &Events::listen_requestMouse, &m_sSeat, "Seat");
addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat");
@@ -197,9 +204,13 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRPointerConstraints->events.new_constraint, &Events::listen_newConstraint, m_sWLRPointerConstraints, "PointerConstraints");
addWLSignal(&m_sWLRXDGDecoMgr->events.new_toplevel_decoration, &Events::listen_NewXDGDeco, m_sWLRXDGDecoMgr, "XDGDecoMgr");
addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr");
addWLSignal(&m_sWLRVKeyboardMgr->events.new_virtual_keyboard, &Events::listen_newVirtualKeyboard, m_sWLRVKeyboardMgr, "VKeyboardMgr");
addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer");
addWLSignal(&m_sWLRIdleInhibitMgr->events.new_inhibitor, &Events::listen_newIdleInhibitor, m_sWLRIdleInhibitMgr, "WLRIdleInhibitMgr");
addWLSignal(&m_sWLROutputPowerMgr->events.set_mode, &Events::listen_powerMgrSetMode, m_sWLROutputPowerMgr, "PowerMgr");
addWLSignal(&m_sWLRIMEMgr->events.input_method, &Events::listen_newIME, m_sWLRIMEMgr, "IMEMgr");
addWLSignal(&m_sWLRTextInputMgr->events.text_input, &Events::listen_newTextInput, m_sWLRTextInputMgr, "TextInputMgr");
if (m_sWLRSession)
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
}
@@ -222,6 +233,14 @@ void CCompositor::cleanup() {
wl_display_terminate(m_sWLDisplay);
m_sWLDisplay = nullptr;
// kill the PID with a sigkill after 2 seconds
const auto PID = getpid();
std::string call = "sleep 2 && kill -9 " + std::to_string(PID);
execl("/bin/sh", "/bin/sh", "-c", call.c_str(), ">", "/dev/null", nullptr); // this is to prevent that random "freezing"
// the PID should not be reused.
}
void CCompositor::startCompositor() {
@@ -460,13 +479,13 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceOpen) {
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->m_bHidden && (*w)->m_iX11Type != 2)
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->m_bHidden && !(*w)->m_bX11ShouldntFocus)
return (*w).get();
}
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bHidden && w->m_iX11Type != 2)
if (!w->m_bIsFloating && w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bHidden && !w->m_bX11ShouldntFocus)
return w.get();
}
}
@@ -474,7 +493,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if ((*w)->m_bIsFloating && (*w)->m_bIsMapped && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && (*w)->m_iX11Type != 2) {
if ((*w)->m_bIsFloating && (*w)->m_bIsMapped && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && !(*w)->m_bX11ShouldntFocus) {
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y))
return w->get();
@@ -492,7 +511,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// for windows, we need to check their extensions too, first.
for (auto& w : m_vWindows) {
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bHidden && w->m_iX11Type != 2) {
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bHidden && !w->m_bX11ShouldntFocus) {
wlr_surface* resultSurf = nullptr;
Vector2D origin = w->m_vRealPosition.vec();
SExtensionFindingData data = {origin, pos, &resultSurf};
@@ -504,7 +523,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
}
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bHidden && w->m_iX11Type != 2)
if (!w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bHidden && !w->m_bX11ShouldntFocus)
return w.get();
}
@@ -604,7 +623,19 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
}
if (!pWindow || !windowValidMapped(pWindow)) {
const auto PLASTWINDOW = m_pLastWindow;
m_pLastWindow = nullptr;
if (windowValidMapped(PLASTWINDOW)) {
updateWindowAnimatedDecorationValues(PLASTWINDOW);
if (PLASTWINDOW->m_phForeignToplevel)
wlr_foreign_toplevel_handle_v1_set_activated(PLASTWINDOW->m_phForeignToplevel, false);
}
wlr_seat_keyboard_notify_clear_focus(m_sSeat.seat);
m_pLastFocus = nullptr;
return;
}
@@ -616,6 +647,9 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
if (m_pLastWindow == pWindow && m_sSeat.seat->keyboard_state.focused_surface == pSurface)
return;
if (!isWorkspaceVisible(pWindow->m_iWorkspaceID))
g_pKeybindManager->changeworkspace("[internal]" + std::to_string(pWindow->m_iWorkspaceID));
const auto PLASTWINDOW = m_pLastWindow;
m_pLastWindow = pWindow;
@@ -665,6 +699,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
if (!pSurface) {
wlr_seat_keyboard_clear_focus(m_sSeat.seat);
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused
g_pInputManager->m_sIMERelay.onKeyboardFocus(nullptr);
return;
}
@@ -676,12 +711,14 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
wlr_seat_keyboard_notify_enter(m_sSeat.seat, pSurface, KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers);
g_pInputManager->m_sIMERelay.onKeyboardFocus(pSurface);
wlr_seat_keyboard_focus_change_event event = {
.seat = m_sSeat.seat,
.old_surface = m_pLastFocus,
.new_surface = pSurface,
};
wlr_signal_emit_safe(&m_sSeat.seat->keyboard_state.events.focus_change, &event);
wl_signal_emit_mutable(&m_sSeat.seat->keyboard_state.events.focus_change, &event);
if (pWindowOwner)
Debug::log(LOG, "Set keyboard focus to surface %x, with window name: %s", pSurface, pWindowOwner->m_szTitle.c_str());
@@ -819,31 +856,6 @@ CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) {
return nullptr;
}
void CCompositor::fixXWaylandWindowsOnWorkspace(const int& id) {
// not needed anymore
return;
const auto ISVISIBLE = isWorkspaceVisible(id);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!PWORKSPACE)
return;
for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == id) {
// moveXWaylandWindow only moves XWayland windows
// so there is no need to check here
// if the window is XWayland or not.
if (ISVISIBLE && (!PWORKSPACE->m_bHasFullscreenWindow || w->m_bIsFullscreen))
g_pXWaylandManager->moveXWaylandWindow(w.get(), w->m_vRealPosition.vec());
else
g_pXWaylandManager->moveXWaylandWindow(w.get(), Vector2D(42069,42069));
}
}
}
bool CCompositor::doesSeatAcceptInput(wlr_surface* surface) {
return !m_sSeat.exclusiveClient || (surface && m_sSeat.exclusiveClient == wl_resource_get_client(surface->resource));
}
@@ -1281,7 +1293,7 @@ void CCompositor::moveWindowToWorkspace(CWindow* pWindow, const std::string& wor
int CCompositor::getNextAvailableMonitorID() {
int64_t topID = -1;
for (auto& m : m_vMonitors) {
for (auto& m : m_vRealMonitors) {
if ((int64_t)m->ID > topID)
topID = m->ID;
}
@@ -1338,6 +1350,8 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
if (w->m_bIsFloating && w->m_bIsMapped && !w->m_bHidden) {
w->m_vRealPosition = w->m_vRealPosition.vec() - POLDMON->vecPosition + pMonitor->vecPosition;
}
w->updateToplevel();
}
}
@@ -1380,14 +1394,19 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
if (!windowValidMapped(pWindow))
return;
focusWindow(pWindow);
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, mode, on);
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL);
// make all windows on the same workspace under the fullscreen window
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID)
w->m_bCreatedOverFullscreen = false;
}
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv(), true);
}
void CCompositor::moveUnmanagedX11ToWindows(CWindow* pWindow) {
@@ -1518,3 +1537,80 @@ void CCompositor::warpCursorTo(const Vector2D& pos) {
wlr_cursor_warp(m_sWLRCursor, m_sSeat.mouse->mouse, pos.x, pos.y);
}
SLayerSurface* CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) {
for (auto& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLists) {
for (auto& ls : lsl) {
if (ls->layerSurface == pLS)
return ls.get();
}
}
}
return nullptr;
}
void CCompositor::closeWindow(CWindow* pWindow) {
if (pWindow && windowValidMapped(pWindow)) {
g_pXWaylandManager->sendCloseWindow(pWindow);
if (pWindow == m_pLastWindow) {
m_pLastFocus = nullptr;
m_pLastWindow = nullptr;
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // post an activewindow event to empty, as we are currently unfocused
focusWindow(windowFromCursor());
}
}
}
SLayerSurface* CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) {
for (auto& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLists) {
for (auto& ls : lsl) {
if (ls->layerSurface && ls->layerSurface->surface == pSurface)
return ls.get();
}
}
}
return nullptr;
}
// returns a delta
Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, const Vector2D& relativeTo) {
if (!args.contains(' '))
return relativeTo;
std::string x = args.substr(0, args.find_first_of(' '));
std::string y = args.substr(args.find_first_of(' ') + 1);
if (x == "exact") {
std::string newX = y.substr(0, y.find_first_of(' '));
std::string newY = y.substr(y.find_first_of(' ') + 1);
if (!isNumber(newX) || !isNumber(newY)) {
Debug::log(ERR, "parseWindowVectorArgsRelative: exact args not numbers");
return relativeTo;
}
const int X = std::stoi(newX);
const int Y = std::stoi(newY);
if (X < 0 || Y < 0) {
Debug::log(ERR, "parseWindowVectorArgsRelative: exact args cannot be < 0");
return relativeTo;
}
return Vector2D(X, Y);
}
if (!isNumber(x) || !isNumber(y)) {
Debug::log(ERR, "parseWindowVectorArgsRelative: args not numbers");
return relativeTo;
}
const int X = std::stoi(x);
const int Y = std::stoi(y);
return Vector2D(X + relativeTo.x, Y + relativeTo.y);
}

View File

@@ -66,6 +66,8 @@ public:
wlr_idle_inhibit_manager_v1* m_sWLRIdleInhibitMgr;
wlr_pointer_gestures_v1* m_sWLRPointerGestures;
wlr_output_power_manager_v1* m_sWLROutputPowerMgr;
wlr_input_method_manager_v2* m_sWLRIMEMgr;
wlr_text_input_manager_v3* m_sWLRTextInputMgr;
// ------------------------------------------------- //
@@ -95,6 +97,7 @@ public:
bool m_bReadyToProcess = false;
bool m_bSessionActive = true;
bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
// ------------------------------------------------- //
@@ -125,7 +128,6 @@ public:
void updateWorkspaceWindowDecos(const int&);
int getWindowsOnWorkspace(const int&);
CWindow* getFirstWindowOnWorkspace(const int&);
void fixXWaylandWindowsOnWorkspace(const int&);
CWindow* getFullscreenWindowOnWorkspace(const int&);
bool doesSeatAcceptInput(wlr_surface*);
bool isWindowActive(CWindow*);
@@ -153,6 +155,11 @@ public:
void addToFadingOutSafe(CWindow*);
CWindow* getWindowByRegex(const std::string&);
void warpCursorTo(const Vector2D&);
SLayerSurface* getLayerSurfaceFromWlr(wlr_layer_surface_v1*);
SLayerSurface* getLayerSurfaceFromSurface(wlr_surface*);
void closeWindow(CWindow*);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
std::string explicitConfigPath;

View File

@@ -112,4 +112,97 @@ IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) {
}
return nullptr;
}
void CWindow::createToplevelHandle() {
if (m_bIsX11 && (m_bX11DoesntWantBorders || m_iX11Type == 2))
return; // don't create a toplevel
m_phForeignToplevel = wlr_foreign_toplevel_handle_v1_create(g_pCompositor->m_sWLRToplevelMgr);
wlr_foreign_toplevel_handle_v1_set_app_id(m_phForeignToplevel, g_pXWaylandManager->getAppIDClass(this).c_str());
wlr_foreign_toplevel_handle_v1_output_enter(m_phForeignToplevel, g_pCompositor->getMonitorFromID(m_iMonitorID)->output);
wlr_foreign_toplevel_handle_v1_set_title(m_phForeignToplevel, m_szTitle.c_str());
wlr_foreign_toplevel_handle_v1_set_maximized(m_phForeignToplevel, false);
wlr_foreign_toplevel_handle_v1_set_minimized(m_phForeignToplevel, false);
wlr_foreign_toplevel_handle_v1_set_fullscreen(m_phForeignToplevel, false);
// handle events
hyprListener_toplevelActivate.initCallback(&m_phForeignToplevel->events.request_activate, [&](void* owner, void* data) {
g_pCompositor->focusWindow(this);
}, this, "Toplevel");
hyprListener_toplevelFullscreen.initCallback(&m_phForeignToplevel->events.request_fullscreen, [&](void* owner, void* data) {
const auto EV = (wlr_foreign_toplevel_handle_v1_fullscreen_event*)data;
g_pCompositor->setWindowFullscreen(this, EV->fullscreen, FULLSCREEN_FULL);
}, this, "Toplevel");
hyprListener_toplevelClose.initCallback(&m_phForeignToplevel->events.request_close, [&](void* owner, void* data) {
g_pCompositor->closeWindow(this);
}, this, "Toplevel");
m_iLastToplevelMonitorID = m_iMonitorID;
}
void CWindow::destroyToplevelHandle() {
if (!m_phForeignToplevel)
return;
hyprListener_toplevelActivate.removeCallback();
hyprListener_toplevelClose.removeCallback();
hyprListener_toplevelFullscreen.removeCallback();
wlr_foreign_toplevel_handle_v1_destroy(m_phForeignToplevel);
m_phForeignToplevel = nullptr;
}
void CWindow::updateToplevel() {
updateSurfaceOutputs();
if (!m_phForeignToplevel)
return;
wlr_foreign_toplevel_handle_v1_set_title(m_phForeignToplevel, m_szTitle.c_str());
wlr_foreign_toplevel_handle_v1_set_fullscreen(m_phForeignToplevel, m_bIsFullscreen);
if (m_iLastToplevelMonitorID != m_iMonitorID) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iLastToplevelMonitorID); PMONITOR && PMONITOR->m_bEnabled)
wlr_foreign_toplevel_handle_v1_output_leave(m_phForeignToplevel, PMONITOR->output);
wlr_foreign_toplevel_handle_v1_output_enter(m_phForeignToplevel, g_pCompositor->getMonitorFromID(m_iMonitorID)->output);
m_iLastToplevelMonitorID = m_iMonitorID;
}
}
void sendEnterIter(wlr_surface* pSurface, int x, int y, void* data) {
const auto OUTPUT = (wlr_output*)data;
wlr_surface_send_enter(pSurface, OUTPUT);
}
void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
const auto OUTPUT = (wlr_output*)data;
wlr_surface_send_leave(pSurface, OUTPUT);
}
void CWindow::updateSurfaceOutputs() {
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden || !m_bMappedX11)
return;
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
m_iLastSurfaceMonitorID = m_iMonitorID;
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(this), sendLeaveIter, PLASTMONITOR->output);
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(this), sendEnterIter, PNEWMONITOR->output);
}

View File

@@ -13,6 +13,7 @@ struct SWindowSpecialRenderData {
// set by the layout
bool rounding = true;
bool border = true;
};
struct SWindowAdditionalConfigData {
@@ -39,6 +40,11 @@ public:
DYNLISTENER(requestMinimize);
DYNLISTENER(requestMaximize);
DYNLISTENER(requestResize);
DYNLISTENER(activateX11);
DYNLISTENER(configureX11);
DYNLISTENER(toplevelClose);
DYNLISTENER(toplevelActivate);
DYNLISTENER(toplevelFullscreen);
// DYNLISTENER(newSubsurfaceWindow);
union {
@@ -58,6 +64,9 @@ public:
Vector2D m_vReportedPosition;
Vector2D m_vReportedSize;
// for restoring floating statuses
Vector2D m_vLastFloatingSize;
// this is used for pseudotiling
bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(0,0);
@@ -84,8 +93,7 @@ public:
uint64_t m_iX11Type = 0;
bool m_bIsModal = false;
bool m_bX11DoesntWantBorders = false;
DYNLISTENER(activateX11);
DYNLISTENER(configureX11);
bool m_bX11ShouldntFocus = false;
//
// For nofocus
@@ -124,6 +132,10 @@ public:
// animated shadow color
CAnimatedVariable m_cRealShadowColor;
// for toplevel monitor events
uint64_t m_iLastToplevelMonitorID = -1;
uint64_t m_iLastSurfaceMonitorID = -1;
// For the list lookup
bool operator==(const CWindow& rhs) {
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut;
@@ -135,5 +147,8 @@ public:
void updateWindowDecos();
pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType);
void createToplevelHandle();
void destroyToplevelHandle();
void updateToplevel();
void updateSurfaceOutputs();
};

View File

@@ -54,6 +54,9 @@ void CConfigManager::setDefaultVars() {
configValues["misc:no_vfr"].intValue = 1;
configValues["misc:damage_entire_on_snapshot"].intValue = 0;
configValues["misc:mouse_move_enables_dpms"].intValue = 0;
configValues["misc:always_follow_on_dnd"].intValue = 1;
configValues["misc:layers_hog_keyboard_focus"].intValue = 1;
configValues["misc:animate_manual_resizes"].intValue = 0;
configValues["debug:int"].intValue = 0;
configValues["debug:log_damage"].intValue = 0;
@@ -89,6 +92,7 @@ void CConfigManager::setDefaultVars() {
configValues["dwindle:special_scale_factor"].floatValue = 0.8f;
configValues["dwindle:split_width_multiplier"].floatValue = 1.0f;
configValues["dwindle:no_gaps_when_only"].intValue = 0;
configValues["dwindle:use_active_for_splits"].intValue = 1;
configValues["master:special_scale_factor"].floatValue = 0.8f;
configValues["master:new_is_master"].intValue = 1;
@@ -116,6 +120,7 @@ void CConfigManager::setDefaultVars() {
configValues["animations:workspaces"].intValue = 1;
configValues["input:sensitivity"].floatValue = 0.f;
configValues["input:kb_file"].strValue = STRVAL_EMPTY;
configValues["input:kb_layout"].strValue = "us";
configValues["input:kb_variant"].strValue = STRVAL_EMPTY;
configValues["input:kb_options"].strValue = STRVAL_EMPTY;
@@ -152,6 +157,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
auto& cfgValues = deviceConfigs[dev];
cfgValues["sensitivity"].floatValue = 0.f;
cfgValues["kb_file"].strValue = STRVAL_EMPTY;
cfgValues["kb_layout"].strValue = "us";
cfgValues["kb_variant"].strValue = STRVAL_EMPTY;
cfgValues["kb_options"].strValue = STRVAL_EMPTY;
@@ -433,13 +439,8 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
return;
}
// overwrite if exists
for (auto& r : m_dMonitorRules) {
if (r.name == newrule.name) {
r = newrule;
return;
}
}
if (std::find_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }) != m_dMonitorRules.end())
m_dMonitorRules.erase(std::remove_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }));
m_dMonitorRules.push_back(newrule);
@@ -454,17 +455,31 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
if (curitem.contains("@"))
newrule.refreshRate = stof(curitem.substr(curitem.find_first_of('@') + 1));
}
}
nextItem();
newrule.offset.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
newrule.offset.y = stoi(curitem.substr(curitem.find_first_of('x') + 1));
if (curitem.find("auto") == 0) {
newrule.offset = Vector2D(-1, -1);
} else {
newrule.offset.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
newrule.offset.y = stoi(curitem.substr(curitem.find_first_of('x') + 1));
if (newrule.offset.x < 0 || newrule.offset.y < 0) {
parseError = "invalid offset. Offset cannot be negative.";
newrule.offset = Vector2D();
}
}
nextItem();
newrule.scale = stof(curitem);
if (newrule.scale < 0.25f) {
parseError = "not a valid scale.";
newrule.scale = 1;
}
nextItem();
if (curitem != "") {
@@ -474,13 +489,8 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
return;
}
// overwrite if exists
for (auto& r : m_dMonitorRules) {
if (r.name == newrule.name) {
r = newrule;
return;
}
}
if (std::find_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }) != m_dMonitorRules.end())
m_dMonitorRules.erase(std::remove_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }));
m_dMonitorRules.push_back(newrule);
}
@@ -507,13 +517,24 @@ void CConfigManager::handleBezier(const std::string& command, const std::string&
std::string bezierName = curitem;
nextItem();
if (curitem == "")
parseError = "too few arguments";
float p1x = std::stof(curitem);
nextItem();
if (curitem == "")
parseError = "too few arguments";
float p1y = std::stof(curitem);
nextItem();
if (curitem == "")
parseError = "too few arguments";
float p2x = std::stof(curitem);
nextItem();
if (curitem == "")
parseError = "too few arguments";
float p2y = std::stof(curitem);
nextItem();
if (curitem != "")
parseError = "too many arguments";
g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y));
}
@@ -568,14 +589,23 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
// on/off
PANIM->second.internalEnabled = curitem == "1";
if (curitem != "0" && curitem != "1") {
parseError = "invalid animation on/off state";
}
nextItem();
// speed
if (isNumber(curitem, true)) {
PANIM->second.internalSpeed = std::stof(curitem);
if (PANIM->second.internalSpeed <= 0) {
parseError = "invalid speed";
PANIM->second.internalSpeed = 1.f;
}
} else {
PANIM->second.internalSpeed = 10.f;
parseError = "Invalid speed";
parseError = "invalid speed";
}
nextItem();
@@ -583,11 +613,23 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
// curve
PANIM->second.internalBezier = curitem;
if (!g_pAnimationManager->bezierExists(curitem)) {
parseError = "no such bezier";
PANIM->second.internalBezier = "default";
}
nextItem();
// style
PANIM->second.internalStyle = curitem;
if (curitem != "") {
const auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, curitem);
if (ERR != "")
parseError = ERR;
}
// now, check for children, recursively
setAnimForChildren(&PANIM->second);
}
@@ -735,28 +777,13 @@ void CConfigManager::handleSubmap(const std::string& command, const std::string&
void CConfigManager::handleSource(const std::string& command, const std::string& rawpath) {
static const char* const ENVHOME = getenv("HOME");
auto value = rawpath;
if (value.length() < 2) {
if (rawpath.length() < 2) {
Debug::log(ERR, "source= path garbage");
parseError = "source path " + value + " bogus!";
parseError = "source path " + rawpath + " bogus!";
return;
}
if (value[0] == '.') {
auto currentDir = configCurrentPath.substr(0, configCurrentPath.find_last_of('/'));
if (value[1] == '.') {
auto parentDir = currentDir.substr(0, currentDir.find_last_of('/'));
value.replace(0, 2, parentDir);
} else {
value.replace(0, 1, currentDir);
}
}
if (value[0] == '~') {
value.replace(0, 1, std::string(ENVHOME));
}
auto value = absolutePath(rawpath, configCurrentPath);
if (!std::filesystem::exists(value)) {
Debug::log(ERR, "source= file doesnt exist");
@@ -885,6 +912,7 @@ void CConfigManager::parseLine(std::string& line) {
if (line.contains(" {")) {
auto cat = line.substr(0, line.find(" {"));
transform(cat.begin(), cat.end(), cat.begin(), ::tolower);
std::replace(cat.begin(), cat.end(), ' ', '-');
if (currentCategory.length() != 0) {
currentCategory.push_back(':');
currentCategory.append(cat);
@@ -1034,14 +1062,15 @@ void CConfigManager::loadConfigLoadVars() {
if (parseError != "")
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255));
else if (configValues["autogenerated"].intValue == 1)
g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + CONFIGPATH + " )\nSUPER+Enter -> kitty\nSUPER+T -> Alacritty\nSUPER+M -> exit Hyprland", CColor(255, 255, 70, 255));
g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + CONFIGPATH + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland", CColor(255, 255, 70, 255));
else
g_pHyprError->destroy();
// Set the modes for all monitors as we configured them
// not on first launch because monitors might not exist yet
// and they'll be taken care of in the newMonitor event
if (!isFirstLaunch) {
// ignore if nomonitorreload is set
if (!isFirstLaunch && !m_bNoMonitorReload) {
m_bWantsMonitorReload = true;
// check
@@ -1061,6 +1090,9 @@ void CConfigManager::loadConfigLoadVars() {
// Force the compositor to fully re-render all monitors
for (auto& m : g_pCompositor->m_vMonitors)
m->forceFullFrames = 2;
// Reset no monitor reload
m_bNoMonitorReload = false;
}
void CConfigManager::tick() {
@@ -1109,9 +1141,13 @@ SConfigValue CConfigManager::getConfigValueSafe(const std::string& val) {
SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val) {
std::lock_guard<std::mutex> lg(configmtx);
const auto it = deviceConfigs.find(dev);
auto devcopy = dev;
std::replace(devcopy.begin(), devcopy.end(), ' ', '-');
const auto it = deviceConfigs.find(devcopy);
if (it == deviceConfigs.end()) {
Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", devcopy.c_str());
return SConfigValue();
}
@@ -1124,7 +1160,7 @@ SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, co
if (foundIt == std::string::npos)
continue;
if (foundIt == cv.first.length() - val.length()) {
if (cv.first == "input:" + val || cv.first == "input:touchpad:" + cv.first) {
copy = cv.second;
}
}
@@ -1206,7 +1242,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(std::string name) {
Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
return SMonitorRule{.name = "", .resolution = Vector2D(1280, 720), .offset = Vector2D(0, 0), .scale = 1};
return SMonitorRule{.name = "", .resolution = Vector2D(0, 0), .offset = Vector2D(-1, -1), .scale = 1}; // 0, 0 is preferred and -1, -1 is auto
}
std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
@@ -1275,7 +1311,7 @@ void CConfigManager::performMonitorReload() {
bool overAgain = false;
for (auto& m : g_pCompositor->m_vMonitors) {
for (auto& m : g_pCompositor->m_vRealMonitors) {
auto rule = getMonitorRuleFor(m->szName);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
overAgain = true;
@@ -1293,8 +1329,20 @@ SConfigValue* CConfigManager::getConfigValuePtr(std::string val) {
return &configValues[val];
}
SConfigValue* CConfigManager::getConfigValuePtrSafe(std::string val) {
const auto IT = configValues.find(val);
if (IT == configValues.end())
return nullptr;
return &(IT->second);
}
bool CConfigManager::deviceConfigExists(const std::string& dev) {
const auto it = deviceConfigs.find(dev);
auto copy = dev;
std::replace(copy.begin(), copy.end(), ' ', '-');
const auto it = deviceConfigs.find(copy);
return it != deviceConfigs.end();
}
@@ -1314,7 +1362,7 @@ void CConfigManager::ensureDPMS() {
auto rule = getMonitorRuleFor(rm->szName);
if (rule.disabled == rm->m_bEnabled) {
rm->m_pThisWrap = &rm;
rm->m_pThisWrap = &rm;
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
}
}
@@ -1323,3 +1371,8 @@ void CConfigManager::ensureDPMS() {
SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::string& name) {
return &animationConfig[name];
}
void CConfigManager::addParseError(const std::string& err) {
if (parseError == "")
parseError = err;
}

View File

@@ -83,6 +83,7 @@ public:
bool shouldBlurLS(const std::string&);
SConfigValue* getConfigValuePtr(std::string);
SConfigValue* getConfigValuePtrSafe(std::string);
SMonitorRule getMonitorRuleFor(std::string);
@@ -96,11 +97,17 @@ public:
void performMonitorReload();
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
void ensureDPMS();
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
void addParseError(const std::string&);
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
std::string configCurrentPath;
private:
std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
@@ -110,8 +117,6 @@ private:
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
std::string configCurrentPath;
std::string currentCategory = ""; // For storing the category of the current item
std::string parseError = ""; // For storing a parse error to display later
@@ -131,7 +136,6 @@ private:
void setDefaultVars();
void setDefaultAnimationVars();
void setDeviceDefaultVars(const std::string&);
void ensureDPMS();
void setAnimForChildren(SAnimationPropertyConfig *const);
@@ -155,4 +159,4 @@ private:
void handleBlurLS(const std::string&, const std::string&);
};
inline std::unique_ptr<CConfigManager> g_pConfigManager;
inline std::unique_ptr<CConfigManager> g_pConfigManager;

View File

@@ -17,9 +17,10 @@ OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
autogenerated=1 # remove this line to get rid of the warning on top.
monitor=,preferred,0x0,1
monitor=,preferred,auto,1
input {
kb_file=
kb_layout=
kb_variant=
kb_model=
@@ -122,4 +123,4 @@ bind=ALT,0,movetoworkspace,10
bind=SUPER,mouse_down,workspace,e+1
bind=SUPER,mouse_up,workspace,e-1
)#";
)#";

View File

@@ -35,7 +35,7 @@ R"#({
"reserved": [%i, %i, %i, %i],
"scale": %.2f,
"transform": %i,
"active": "%s"
"focused": %s
},)#",
m->ID,
escapeJSONStrings(m->szName).c_str(),
@@ -46,7 +46,7 @@ R"#({
(int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y,
m->scale,
(int)m->transform,
(m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no")
(m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false")
);
}
@@ -56,7 +56,7 @@ R"#({
result += "]";
} else {
for (auto& m : g_pCompositor->m_vMonitors) {
result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\tactive: %s\n\n",
result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\tfocused: %s\n\n",
m->szName.c_str(), m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName.c_str(), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"));
}
}
@@ -80,29 +80,30 @@ R"#({
"id": %i,
"name": "%s"
},
"floating": %i,
"floating": %s,
"monitor": %i,
"class": "%s",
"title": "%s",
"pid": %i,
"xwayland": %i
"xwayland": %s
},)#",
w.get(),
(int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y,
(int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y,
w->m_iWorkspaceID, escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))).c_str(),
(int)w->m_bIsFloating,
((int)w->m_bIsFloating == 1 ? "true" : "false"),
w->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(),
w->getPID(),
(int)w->m_bIsX11
((int)w->m_bIsX11 == 1 ? "true" : "false")
);
}
}
// remove trailing comma
result.pop_back();
if (result != "[")
result.pop_back();
result += "]";
} else {
@@ -129,13 +130,13 @@ R"#({
"name": "%s",
"monitor": "%s",
"windows": %i,
"hasfullscreen": %i
"hasfullscreen": %s
},)#",
w->m_iID,
escapeJSONStrings(w->m_szName).c_str(),
escapeJSONStrings(g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName).c_str(),
g_pCompositor->getWindowsOnWorkspace(w->m_iID),
(int)w->m_bHasFullscreenWindow
((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false")
);
}
@@ -156,7 +157,7 @@ std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
return "Invalid";
return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid";
if (format == HyprCtl::FORMAT_JSON) {
return getFormat(
@@ -168,23 +169,23 @@ R"#({
"id": %i,
"name": "%s"
},
"floating": %i,
"floating": %s,
"monitor": %i,
"class": "%s",
"title": "%s",
"pid": %i,
"xwayland": %i
"xwayland": %s
})#",
PWINDOW,
(int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y,
(int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y,
PWINDOW->m_iWorkspaceID, escapeJSONStrings(PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName).c_str(),
(int)PWINDOW->m_bIsFloating,
((int)PWINDOW->m_bIsFloating == 1 ? "true" : "false"),
PWINDOW->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(),
PWINDOW->getPID(),
(int)PWINDOW->m_bIsX11
((int)PWINDOW->m_bIsX11 == 1 ? "true" : "false")
);
} else {
return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\n",
@@ -299,7 +300,7 @@ R"#( {
result += "\"keyboards\": [\n";
for (auto& k : g_pInputManager->m_lKeyboards) {
const auto KM = xkb_keymap_layout_get_name(wlr_keyboard_from_input_device(k.keyboard)->keymap, 0);
const auto KM = g_pInputManager->getActiveLayoutForKeyboard(&k);
result += getFormat(
R"#( {
"address": "0x%x",
@@ -309,7 +310,8 @@ R"#( {
"layout": "%s",
"variant": "%s",
"options": "%s",
"active_keymap": "%s"
"active_keymap": "%s",
"main": %s
},)#",
&k,
escapeJSONStrings(k.keyboard->name).c_str(),
@@ -318,7 +320,8 @@ R"#( {
escapeJSONStrings(k.currentRules.layout).c_str(),
escapeJSONStrings(k.currentRules.variant).c_str(),
escapeJSONStrings(k.currentRules.options).c_str(),
escapeJSONStrings(KM).c_str()
escapeJSONStrings(KM).c_str(),
(k.active ? "true" : "false")
);
}
@@ -384,8 +387,8 @@ R"#( {
result += "\n\nKeyboards:\n";
for (auto& k : g_pInputManager->m_lKeyboards) {
const auto KM = xkb_keymap_layout_get_name(wlr_keyboard_from_input_device(k.keyboard)->keymap, 0);
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n", &k, k.keyboard->name, k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM);
const auto KM = g_pInputManager->getActiveLayoutForKeyboard(&k);
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n\t\t\tmain: %s\n", &k, k.keyboard->name, k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM.c_str(), (k.active ? "yes" : "no"));
}
result += "\n\nTablets:\n";
@@ -406,23 +409,56 @@ R"#( {
return result;
}
std::string versionRequest() {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + GIT_DIRTY + " (" + GIT_COMMIT_MESSAGE + ").\nflags: (if any)\n";
std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + GIT_DIRTY + " (" + removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE).c_str() + ").\nflags: (if any)\n";
#ifdef LEGACY_RENDERER
result += "legacyrenderer\n";
result += "legacyrenderer\n";
#endif
#ifndef NDEBUG
result += "debug\n";
result += "debug\n";
#endif
#ifdef HYPRLAND_DEBUG
result += "debug\n";
result += "debug\n";
#endif
#ifdef NO_XWAYLAND
result += "no xwayland\n";
result += "no xwayland\n";
#endif
return result;
return result;
} else {
std::string result = getFormat(
R"#({
"branch": "%s",
"commit": "%s",
"dirty": %s
"commit_message": "%s",
"flags": [)#", GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE).c_str());
#ifdef LEGACY_RENDERER
result += "\"legacyrenderer\",";
#endif
#ifndef NDEBUG
result += "\"debug\",";
#endif
#ifdef HYPRLAND_DEBUG
result += "\"debug\",";
#endif
#ifdef NO_XWAYLAND
result += "\"no xwayland\",";
#endif
if (result[result.length() - 1] == ',')
result.pop_back();
result += "]\n}";
return result;
}
return ""; // make the compiler happy
}
std::string dispatchRequest(std::string in) {
@@ -457,8 +493,10 @@ std::string dispatchKeyword(std::string in) {
if (COMMAND == "monitor")
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords
if (COMMAND.contains("input"))
if (COMMAND.contains("input") || COMMAND.contains("device:")) {
g_pInputManager->setKeyboardLayout(); // update kb layout
g_pInputManager->setMouseConfigs(); // update mouse cfgs
}
if (COMMAND.contains("general:layout"))
g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout
@@ -471,9 +509,16 @@ std::string dispatchKeyword(std::string in) {
return retval;
}
std::string reloadRequest() {
std::string reloadRequest(std::string request) {
const auto REQMODE = request.substr(request.find_last_of(' ') + 1);
g_pConfigManager->m_bForceReload = true;
if (REQMODE == "config-only") {
g_pConfigManager->m_bNoMonitorReload = true;
}
return "ok";
}
@@ -521,6 +566,97 @@ std::string dispatchBatch(std::string request) {
return reply;
}
std::string dispatchSetCursor(std::string request) {
std::string curitem = "";
auto nextItem = [&]() {
auto idx = request.find_first_of(' ');
if (idx != std::string::npos) {
curitem = request.substr(0, idx);
request = request.substr(idx + 1);
} else {
curitem = request;
request = "";
}
curitem = removeBeginEndSpacesTabs(curitem);
};
nextItem();
nextItem();
const auto THEME = curitem;
nextItem();
const auto SIZE = curitem;
if (!isNumber(SIZE)) {
return "size not int";
}
const auto SIZEINT = std::stoi(SIZE);
if (SIZEINT < 1) {
return "size must be positive";
}
wlr_xcursor_manager_destroy(g_pCompositor->m_sWLRXCursorMgr);
g_pCompositor->m_sWLRXCursorMgr = wlr_xcursor_manager_create(THEME.c_str(), SIZEINT);
setenv("XCURSOR_SIZE", SIZE.c_str(), true);
setenv("XCURSOR_THEME", THEME.c_str(), true);
for (auto& m : g_pCompositor->m_vMonitors) {
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, m->scale);
}
return "ok";
}
std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
std::string curitem = "";
auto nextItem = [&]() {
auto idx = request.find_first_of(' ');
if (idx != std::string::npos) {
curitem = request.substr(0, idx);
request = request.substr(idx + 1);
} else {
curitem = request;
request = "";
}
curitem = removeBeginEndSpacesTabs(curitem);
};
nextItem();
nextItem();
const auto PCFGOPT = g_pConfigManager->getConfigValuePtrSafe(curitem);
if (!PCFGOPT)
return "no such option";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL)
return getFormat("option %s\n\tint: %i\n\tfloat: %f\n\tstr: \"%s\"", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str());
else {
return getFormat(
R"#(
{
"option": "%s",
"int": %i,
"float": %f,
"str": "%s"
}
)#", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str()
);
}
}
std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL;
@@ -555,9 +691,9 @@ std::string getReply(std::string request) {
else if (request == "layers")
return layersRequest(format);
else if (request == "version")
return versionRequest();
else if (request == "reload")
return reloadRequest();
return versionRequest(format);
else if (request.find("reload") == 0)
return reloadRequest(request);
else if (request == "devices")
return devicesRequest(format);
else if (request == "splash")
@@ -566,6 +702,10 @@ std::string getReply(std::string request) {
return dispatchRequest(request);
else if (request.find("keyword") == 0)
return dispatchKeyword(request);
else if (request.find("setcursor") == 0)
return dispatchSetCursor(request);
else if (request.find("getoption") == 0)
return dispatchGetOption(request, format);
else if (request.find("[[BATCH]]") == 0)
return dispatchBatch(request);
@@ -589,6 +729,10 @@ void HyprCtl::tickHyprCtl() {
requestMade = false;
requestReady = true;
if (g_pConfigManager->m_bWantsMonitorReload) {
g_pConfigManager->ensureDPMS();
}
}
std::string getRequestFromThread(std::string rq) {
@@ -663,4 +807,4 @@ void HyprCtl::startHyprCtlSocket() {
close(SOCKET);
}).detach();
}
}

View File

@@ -72,7 +72,6 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
break;
case WLR_INPUT_DEVICE_TOUCH:
Debug::log(LOG, "Attached a touch device with name %s", DEVICE->name);
Debug::log(WARN, "!!!! Hyprland does not directly support touchscreens, bugs may occur !!!!");
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET_TOOL:
@@ -189,4 +188,22 @@ void Events::listener_pinchUpdate(wl_listener* listener, void* data) {
void Events::listener_pinchEnd(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_pinch_end_event*)data;
wlr_pointer_gestures_v1_send_pinch_end(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, EV->time_msec, EV->cancelled);
}
void Events::listener_newVirtualKeyboard(wl_listener* listener, void* data) {
const auto WLRKB = (wlr_virtual_keyboard_v1*)data;
g_pInputManager->newVirtualKeyboard(&WLRKB->keyboard.base);
}
void Events::listener_touchBegin(wl_listener* listener, void* data) {
g_pInputManager->onTouchDown((wlr_touch_down_event*)data);
}
void Events::listener_touchEnd(wl_listener* listener, void* data) {
g_pInputManager->onTouchUp((wlr_touch_up_event*)data);
}
void Events::listener_touchUpdate(wl_listener* listener, void* data) {
g_pInputManager->onTouchMove((wlr_touch_motion_event*)data);
}

View File

@@ -133,4 +133,20 @@ namespace Events {
// Power
LISTENER(powerMgrSetMode);
// IME
LISTENER(newIME);
LISTENER(newTextInput);
LISTENER(newVirtualKeyboard);
// IME Popups
DYNLISTENFUNC(mapInputPopup);
DYNLISTENFUNC(unmapInputPopup);
DYNLISTENFUNC(commitInputPopup);
DYNLISTENFUNC(destroyInputPopup);
// Touch
LISTENER(touchBegin);
LISTENER(touchEnd);
LISTENER(touchUpdate);
};

View File

@@ -103,6 +103,13 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
g_pInputManager->m_sDrag.hyprListener_destroyIcon.initCallback(&wlrDrag->icon->events.destroy, &Events::listener_destroyDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
g_pInputManager->m_sDrag.hyprListener_commitIcon.initCallback(&wlrDrag->icon->surface->events.commit, &Events::listener_commitDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
}
static auto *const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
if (*PFOLLOWONDND)
g_pInputManager->m_pFollowOnDnDBegin = g_pCompositor->m_pLastWindow;
else
g_pInputManager->m_pFollowOnDnDBegin = nullptr;
}
void Events::listener_destroyDrag(void* owner, void* data) {
@@ -113,6 +120,11 @@ void Events::listener_destroyDrag(void* owner, void* data) {
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
g_pInputManager->refocus();
if (g_pInputManager->m_pFollowOnDnDBegin)
g_pCompositor->focusWindow(g_pInputManager->m_pFollowOnDnDBegin);
g_pInputManager->m_pFollowOnDnDBegin = nullptr;
}
void Events::listener_mapDragIcon(void* owner, void* data) {
@@ -174,4 +186,16 @@ void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
if (!wlr_output_commit(EVENT->output))
Debug::log(ERR, "Couldn't set power mode");
}
void Events::listener_newIME(wl_listener* listener, void* data) {
Debug::log(LOG, "New IME added!");
g_pInputManager->m_sIMERelay.onNewIME((wlr_input_method_v2*)data);
}
void Events::listener_newTextInput(wl_listener* listener, void* data) {
Debug::log(LOG, "New TextInput added!");
g_pInputManager->m_sIMERelay.onNewTextInput((wlr_text_input_v3*)data);
}

View File

@@ -53,33 +53,49 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
return;
}
if (g_pCompositor->getMonitorFromName(std::string(OUTPUT->name))) {
Debug::log(WARN, "Monitor with name %s already exists, not adding as new!", OUTPUT->name);
return;
if (g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Recovering from an unsafe state. May you be lucky.");
}
// add it to real
const auto PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
wlr_output_init_render(OUTPUT, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
for (auto& rm : g_pCompositor->m_vRealMonitors) {
if (rm->szName == OUTPUT->name) {
PNEWMONITORWRAP = &rm;
Debug::log(LOG, "Recovering a removed monitor.");
break;
}
}
if (!PNEWMONITORWRAP) {
Debug::log(LOG, "Adding completely new monitor.");
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
(*PNEWMONITORWRAP)->ID = g_pCompositor->getNextAvailableMonitorID();
}
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
PNEWMONITOR->output = OUTPUT;
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
PNEWMONITOR->onConnect(false);
if (!pMostHzMonitor || PNEWMONITOR->refreshRate > pMostHzMonitor->refreshRate)
if ((!pMostHzMonitor || PNEWMONITOR->refreshRate > pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
pMostHzMonitor = PNEWMONITOR;
// ready to process cuz we have a monitor
g_pCompositor->m_bReadyToProcess = true;
if (PNEWMONITOR->m_bEnabled) {
g_pCompositor->m_bReadyToProcess = true;
g_pCompositor->m_bUnsafeState = false;
}
}
void Events::listener_monitorFrame(void* owner, void* data) {
CMonitor* const PMONITOR = (CMonitor*)owner;
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive) {
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!");
return; // cannot draw on session inactive (different tty)
}
@@ -293,20 +309,23 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
pMonitor->onDisconnect();
// cleanup
g_pCompositor->m_vRealMonitors.erase(std::remove_if(g_pCompositor->m_vRealMonitors.begin(), g_pCompositor->m_vRealMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; }));
// cleanup if not unsafe
if (pMostHzMonitor == pMonitor) {
int mostHz = 0;
CMonitor* pMonitorMostHz = nullptr;
if (!g_pCompositor->m_bUnsafeState) {
g_pCompositor->m_vRealMonitors.erase(std::remove_if(g_pCompositor->m_vRealMonitors.begin(), g_pCompositor->m_vRealMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; }));
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->refreshRate > mostHz) {
pMonitorMostHz = m.get();
mostHz = m->refreshRate;
if (pMostHzMonitor == pMonitor) {
int mostHz = 0;
CMonitor* pMonitorMostHz = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->refreshRate > mostHz) {
pMonitorMostHz = m.get();
mostHz = m->refreshRate;
}
}
}
pMostHzMonitor = pMonitorMostHz;
pMostHzMonitor = pMonitorMostHz;
}
}
}

View File

@@ -59,7 +59,7 @@ void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->vecTransformedSize.x, .height = PMONITOR->vecTransformedSize.y};
wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->vecSize.x, .height = PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(popup, &box);
@@ -151,7 +151,10 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
g_pHyprRenderer->damageBox(lx, ly, PPOPUP->popup->current.geometry.width, PPOPUP->popup->current.geometry.width);
wlr_box extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
g_pHyprRenderer->damageBox(lx, ly, extents.width + 2, extents.height + 2);
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree);
}
@@ -167,7 +170,10 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
g_pHyprRenderer->damageBox(lx, ly, PPOPUP->popup->current.geometry.width, PPOPUP->popup->current.geometry.width);
wlr_box extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
g_pHyprRenderer->damageBox(lx, ly, extents.width + 2, extents.height + 2);
PPOPUP->pSurfaceTree = nullptr;
}

View File

@@ -68,9 +68,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
// Foreign Toplevel
PWINDOW->m_phForeignToplevel = wlr_foreign_toplevel_handle_v1_create(g_pCompositor->m_sWLRToplevelMgr);
// TODO: handle foreign events (requests)
wlr_foreign_toplevel_handle_v1_set_app_id(PWINDOW->m_phForeignToplevel, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
PWINDOW->createToplevelHandle();
// checks if the window wants borders and sets the appriopriate flag
g_pXWaylandManager->checkBorders(PWINDOW);
@@ -87,6 +85,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bRequestsFloat = true;
}
PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2);
if (PWORKSPACE->m_bDefaultFloating)
PWINDOW->m_bIsFloating = true;
@@ -118,13 +118,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_iMonitorID = PMONITOR->ID;
} else {
const long int MONITOR = std::stoi(MONITORSTR);
if (MONITOR >= (long int)g_pCompositor->m_vMonitors.size() || MONITOR < (long int)0)
if (!g_pCompositor->getMonitorFromID(MONITOR))
PWINDOW->m_iMonitorID = 0;
else
PWINDOW->m_iMonitorID = MONITOR;
}
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
Debug::log(ERR, "Rule monitor, applying to window %x -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID);
} catch (std::exception& e) {
@@ -327,6 +328,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(g_pXWaylandManager->getWindowSurface(PWINDOW), addViewCoords, PWINDOW, PWINDOW);
PWINDOW->updateToplevel();
Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, PWINDOW->m_vRealSize.goalv().x, PWINDOW->m_vRealSize.goalv().y);
}
@@ -381,7 +384,17 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->m_bIsMapped = false;
// refocus on a new window
g_pInputManager->refocus();
auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f);
if (!PWINDOWCANDIDATE)
PWINDOWCANDIDATE = g_pCompositor->getFirstWindowOnWorkspace(PWINDOW->m_iWorkspaceID);
if (!PWINDOWCANDIDATE || PWINDOW == PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bIsMapped || PWINDOWCANDIDATE->m_bHidden || PWINDOWCANDIDATE->m_bX11ShouldntFocus || PWINDOWCANDIDATE->m_iX11Type == 2)
PWINDOWCANDIDATE = nullptr;
Debug::log(LOG, "On closed window, new focused candidate is %x", PWINDOWCANDIDATE);
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %x", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
@@ -408,8 +421,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->m_fAlpha = 0.f;
// Destroy Foreign Toplevel
wlr_foreign_toplevel_handle_v1_destroy(PWINDOW->m_phForeignToplevel);
PWINDOW->m_phForeignToplevel = nullptr;
PWINDOW->destroyToplevelHandle();
// recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus();
@@ -465,8 +477,7 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
if (PWINDOW == g_pCompositor->m_pLastWindow) // if it's the active, let's post an event to update others
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle});
if (PWINDOW->m_phForeignToplevel)
wlr_foreign_toplevel_handle_v1_set_title(PWINDOW->m_phForeignToplevel, PWINDOW->m_szTitle.c_str());
PWINDOW->updateToplevel();
Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str());
}
@@ -474,17 +485,22 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
void Events::listener_fullscreenWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bIsMapped || PWINDOW->m_bHidden)
return;
if (!PWINDOW->m_bIsX11) {
const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested;
if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen)
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, REQUESTED->fullscreen);
g_pCompositor->setWindowFullscreen(PWINDOW, REQUESTED->fullscreen, FULLSCREEN_FULL);
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
} else {
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, !PWINDOW->m_bIsFullscreen);
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_FULL);
}
PWINDOW->updateToplevel();
Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen);
g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen);
@@ -511,7 +527,7 @@ void Events::listener_configureX11(void* owner, void* data) {
const auto E = (wlr_xwayland_surface_configure_event*)data;
g_pHyprRenderer->damageWindow(PWINDOW);
if (!PWINDOW->m_bIsFloating) {
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec());
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW);

View File

@@ -40,6 +40,28 @@ static const float transforms[][9] = {{
},
};
std::string absolutePath(const std::string& rawpath, const std::string& currentPath) {
auto value = rawpath;
if (value[0] == '.') {
auto currentDir = currentPath.substr(0, currentPath.find_last_of('/'));
if (value[1] == '.') {
auto parentDir = currentDir.substr(0, currentDir.find_last_of('/'));
value.replace(0, 2, parentDir);
} else {
value.replace(0, 1, currentDir);
}
}
if (value[0] == '~') {
static const char* const ENVHOME = getenv("HOME");
value.replace(0, 1, std::string(ENVHOME));
}
return value;
}
void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) {
ASSERT(pSignal);
ASSERT(pListener);
@@ -53,35 +75,6 @@ void handleNoop(struct wl_listener *listener, void *data) {
// Do nothing
}
void wlr_signal_emit_safe(struct wl_signal *signal, void *data) {
struct wl_listener cursor;
struct wl_listener end;
/* Add two special markers: one cursor and one end marker. This way, we know
* that we've already called listeners on the left of the cursor and that we
* don't want to call listeners on the right of the end marker. The 'it'
* function can remove any element it wants from the list without troubles.
* wl_list_for_each_safe tries to be safe but it fails: it works fine
* if the current item is removed, but not if the next one is. */
wl_list_insert(&signal->listener_list, &cursor.link);
cursor.notify = handleNoop;
wl_list_insert(signal->listener_list.prev, &end.link);
end.notify = handleNoop;
while (cursor.link.next != &end.link) {
struct wl_list *pos = cursor.link.next;
struct wl_listener *l = wl_container_of(pos, l, link);
wl_list_remove(&cursor.link);
wl_list_insert(pos, &cursor.link);
l->notify(l, data);
}
wl_list_remove(&cursor.link);
wl_list_remove(&end.link);
}
std::string getFormat(const char *fmt, ...) {
char* outputStr = nullptr;

View File

@@ -2,8 +2,8 @@
#include "../includes.hpp"
std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, std::string ownerString);
void wlr_signal_emit_safe(struct wl_signal *signal, void *data);
std::string getFormat(const char *fmt, ...); // Basically Debug::log to a string
std::string escapeJSONStrings(const std::string& str);
void scaleBox(wlr_box*, float);
@@ -17,4 +17,4 @@ std::string execAndGet(const char*);
float getPlusMinusKeywordResult(std::string in, float relative);
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);

View File

@@ -3,6 +3,11 @@
#include "../Compositor.hpp"
void CMonitor::onConnect(bool noRule) {
if (m_bEnabled)
return;
szName = output->name;
// get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name);
@@ -11,22 +16,68 @@ void CMonitor::onConnect(bool noRule) {
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
wlr_output_enable_adaptive_sync(output, 1);
wlr_output_set_scale(output, 1);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
auto PREFSTATE = wlr_output_preferred_mode(output);
if (!PREFSTATE) {
wlr_output_mode* mode;
wl_list_for_each(mode, &output->modes, link) {
wlr_output_set_mode(output, PREFSTATE);
if (!wlr_output_test(output))
continue;
PREFSTATE = mode;
break;
}
}
if (PREFSTATE)
wlr_output_set_mode(output, PREFSTATE);
else
Debug::log(WARN, "No mode found for disabled output %s", output->name);
wlr_output_enable(output, 0);
wlr_output_commit(output);
if (!wlr_output_commit(output)) {
Debug::log(ERR, "Couldn't commit disabled state on output %s", output->name);
}
Events::listener_change(nullptr, nullptr);
m_bEnabled = false;
hyprListener_monitorFrame.removeCallback();
return;
}
if (!m_bRenderingInitPassed) {
wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
m_bRenderingInitPassed = true;
}
if (!m_pThisWrap) {
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
m_pThisWrap = &m;
break;
}
}
}
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()){
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
}
m_bEnabled = true;
ID = g_pCompositor->getNextAvailableMonitorID();
szName = output->name;
wlr_output_set_scale(output, monitorRule.scale);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms
@@ -48,7 +99,7 @@ void CMonitor::onConnect(bool noRule) {
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %x", output->name, (int)monitorRule.offset.x, (int)monitorRule.offset.y, (int)monitorRule.resolution.x, (int)monitorRule.resolution.y, output);
Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %x", output->name, (int)vecPosition.x, (int)vecPosition.y, (int)vecPixelSize.x, (int)vecPixelSize.y, output);
damage = wlr_output_damage_create(output);
@@ -96,6 +147,8 @@ void CMonitor::onConnect(bool noRule) {
activeWorkspace = PNEWWORKSPACE->m_iID;
scale = monitorRule.scale;
m_pThisWrap = nullptr;
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
@@ -105,10 +158,19 @@ void CMonitor::onConnect(bool noRule) {
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->m_pLastMonitor = this;
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
g_pHyprRenderer->arrangeLayersForMonitor(ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
}
void CMonitor::onDisconnect() {
if (!m_bEnabled)
return;
// Cleanup everything. Move windows back, snap cursor, shit.
CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) {
@@ -118,16 +180,22 @@ void CMonitor::onDisconnect() {
}
}
if (!BACKUPMON) {
Debug::log(CRIT, "No monitors! Unplugged last! Exiting.");
g_pCompositor->cleanup();
return;
}
m_bEnabled = false;
m_bRenderingInitPassed = false;
hyprListener_monitorFrame.removeCallback();
if (!BACKUPMON) {
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
hyprListener_monitorMode.removeCallback();
hyprListener_monitorDestroy.removeCallback();
g_pCompositor->m_bUnsafeState = true;
return;
}
const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;
// snap cursor

View File

@@ -58,6 +58,7 @@ public:
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
// For the list lookup

View File

@@ -94,11 +94,16 @@ struct SKeyboard {
DYNLISTENER(keyboardMod);
DYNLISTENER(keyboardKey);
DYNLISTENER(keyboardKeymap);
DYNLISTENER(keyboardDestroy);
bool isVirtual = false;
bool active = false;
xkb_layout_index_t activeLayout = 0;
std::string name = "";
std::string xkbFilePath = "";
SStringRuleNames currentRules;
int repeatRate = 0;
@@ -272,4 +277,44 @@ struct SSwipeGesture {
int speedPoints = 0;
CMonitor* pMonitor = nullptr;
};
};
struct STextInput {
wlr_text_input_v3* pWlrInput = nullptr;
wlr_surface* pPendingSurface = nullptr;
DYNLISTENER(textInputEnable);
DYNLISTENER(textInputDisable);
DYNLISTENER(textInputCommit);
DYNLISTENER(textInputDestroy);
DYNLISTENER(pendingSurfaceDestroy);
};
struct SIMEKbGrab {
wlr_input_method_keyboard_grab_v2* pWlrKbGrab = nullptr;
wlr_keyboard* pKeyboard = nullptr;
DYNLISTENER(grabDestroy);
};
struct SIMEPopup {
wlr_input_popup_surface_v2* pSurface = nullptr;
int x, y;
int realX, realY;
bool visible;
DYNLISTENER(mapPopup);
DYNLISTENER(unmapPopup);
DYNLISTENER(destroyPopup);
DYNLISTENER(commitPopup);
DYNLISTENER(focusedSurfaceUnmap);
bool operator==(const SIMEPopup& other) {
return pSurface == other.pSurface;
}
};

View File

@@ -14,6 +14,8 @@ void CHyprError::createQueued() {
const auto PMONITOR = g_pCompositor->m_vMonitors.front().get();
const auto FONTSIZE = std::clamp((int)(10.f * (PMONITOR->vecPixelSize.x / 1920.f)), 8, 40);
const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
const auto CAIRO = cairo_create(CAIROSURFACE);
@@ -27,7 +29,7 @@ void CHyprError::createQueued() {
const auto LINECOUNT = 1 + std::count(m_szQueued.begin(), m_szQueued.end(), '\n');
cairo_set_source_rgba(CAIRO, m_cQueued.r / 255.f, m_cQueued.g / 255.f, m_cQueued.b / 255.f, m_cQueued.a / 255.f);
cairo_rectangle(CAIRO, 0, 0, PMONITOR->vecPixelSize.x, 10 * LINECOUNT);
cairo_rectangle(CAIRO, 0, 0, PMONITOR->vecPixelSize.x, (FONTSIZE + 2 * (FONTSIZE / 10.f)) * LINECOUNT);
// outline
cairo_rectangle(CAIRO, 0, 0, 1, PMONITOR->vecPixelSize.y); // left
@@ -40,10 +42,10 @@ void CHyprError::createQueued() {
const CColor textColor = m_cQueued.r * m_cQueued.g * m_cQueued.b < 0.5f ? CColor(255, 255, 255, 255) : CColor(0, 0, 0, 255);
cairo_select_font_face(CAIRO, "Noto Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(CAIRO, 8);
cairo_set_font_size(CAIRO, FONTSIZE);
cairo_set_source_rgba(CAIRO, textColor.r / 255.f, textColor.g / 255.f, textColor.b / 255.f, textColor.a / 255.f);
float yoffset = 8;
float yoffset = FONTSIZE;
while(m_szQueued != "") {
std::string current = m_szQueued.substr(0, m_szQueued.find('\n'));
if (const auto NEWLPOS = m_szQueued.find('\n'); NEWLPOS != std::string::npos)
@@ -52,7 +54,7 @@ void CHyprError::createQueued() {
m_szQueued = "";
cairo_move_to(CAIRO, 0, yoffset);
cairo_show_text(CAIRO, current.c_str());
yoffset += 9;
yoffset += FONTSIZE + (FONTSIZE / 10.f);
}

View File

@@ -32,6 +32,7 @@
#define class _class
#define namespace _namespace
#define static
#define delete delete_
extern "C" {
#include <wlr/backend.h>
@@ -94,8 +95,12 @@ extern "C" {
#include <wlr/types/wlr_xdg_foreign_v2.h>
#include <wlr/types/wlr_pointer_gestures_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h>
#include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_text_input_v3.h>
#include <wlr/types/wlr_touch.h>
}
#undef delete
#undef class
#undef namespace
#undef static

View File

@@ -1,24 +1,7 @@
#include "DwindleLayout.hpp"
#include "../Compositor.hpp"
void SDwindleNodeData::recalcSizePosRecursive() {
// check the group, if we are in one and not active, ignore.
if (pGroupParent && pGroupParent->groupMembers[pGroupParent->groupMemberActive] != this) {
if (pWindow)
pWindow->m_bHidden = true;
return;
} else {
if (pWindow)
pWindow->m_bHidden = false;
}
if (pGroupParent) {
// means we are in a group and focused. let's just act like the full window in this
size = pGroupParent->size;
position = pGroupParent->position;
}
void SDwindleNodeData::recalcSizePosRecursive(bool force) {
if (children[0]) {
const auto REVERSESPLITRATIO = 2.f - splitRatio;
@@ -44,10 +27,10 @@ void SDwindleNodeData::recalcSizePosRecursive() {
children[1]->size = Vector2D(size.x, size.y / 2.f * REVERSESPLITRATIO);
}
children[0]->recalcSizePosRecursive();
children[1]->recalcSizePosRecursive();
children[0]->recalcSizePosRecursive(force);
children[1]->recalcSizePosRecursive(force);
} else {
layout->applyNodeDataToWindow(this);
layout->applyNodeDataToWindow(this, force);
}
}
@@ -60,6 +43,51 @@ void SDwindleNodeData::getAllChildrenRecursive(std::deque<SDwindleNodeData*>* pD
}
}
bool SDwindleNodeData::isGroupMember() {
return pNextGroupMember && pNextGroupMember != this;
}
SDwindleNodeData* SDwindleNodeData::getGroupHead() {
SDwindleNodeData* current = this->pNextGroupMember;
while (current != this) {
if (current->groupHead) {
return current;
}
current = current->pNextGroupMember;
}
this->groupHead = true;
return this;
}
SDwindleNodeData* SDwindleNodeData::getGroupVisible() {
SDwindleNodeData* current = this->pNextGroupMember;
while (current != this) {
if (!current->pWindow->m_bHidden) {
return current;
}
current = current->pNextGroupMember;
}
return this;
}
void SDwindleNodeData::setGroupFocusedNode(SDwindleNodeData* pMember) {
SDwindleNodeData* current = this->pNextGroupMember;
while (current != this) {
current->pWindow->m_bHidden = current != pMember;
current = current->pNextGroupMember;
}
this->pWindow->m_bHidden = pMember != this;
}
int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) {
int no = 0;
for (auto& n : m_lDwindleNodesData) {
@@ -94,7 +122,7 @@ SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const int& id) {
return nullptr;
}
void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) {
void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool force) {
// Don't set nodes, only windows.
if (pNode->isNode)
return;
@@ -129,7 +157,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) {
const auto PWINDOW = pNode->pWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)) {
if (!g_pCompositor->windowExists(PWINDOW) || !PWINDOW->m_bIsMapped) {
Debug::log(ERR, "Node %x holding invalid window %x!!", pNode, PWINDOW);
return;
}
@@ -143,17 +171,19 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) {
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) {
PWINDOW->m_vRealPosition = calcPos;
PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos - Vector2D(BORDERSIZE, BORDERSIZE);
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
PWINDOW->updateWindowDecos();
PWINDOW->m_sSpecialRenderData.rounding = false;
PWINDOW->m_sSpecialRenderData.border = false;
return;
}
PWINDOW->m_sSpecialRenderData.rounding = true;
PWINDOW->m_sSpecialRenderData.border = true;
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN,
DISPLAYTOP ? GAPSOUT : GAPSIN);
@@ -203,6 +233,19 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) {
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
}
if (force) {
PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealSize.warp();
}
if (pNode->isGroupMember() && pNode->groupHead) {
// update visible node
const auto PVISNODE = pNode->getGroupVisible();
PVISNODE->pWindow->m_vRealSize = PWINDOW->m_vRealSize.goalv();
PVISNODE->pWindow->m_vRealPosition = PWINDOW->m_vRealPosition.goalv();
}
PWINDOW->updateWindowDecos();
}
@@ -215,6 +258,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
static auto *const PUSEACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:use_active_for_splits")->intValue;
// Populate the node with our window's data
PNODE->workspaceID = pWindow->m_iWorkspaceID;
PNODE->pWindow = pWindow;
@@ -224,13 +269,22 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
SDwindleNodeData* OPENINGON;
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromCursor();
if (PMONITOR->ID == MONFROMCURSOR->ID && (PNODE->workspaceID == PMONITOR->activeWorkspace || (PNODE->workspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen))) {
if (PMONITOR->ID == MONFROMCURSOR->ID && (PNODE->workspaceID == PMONITOR->activeWorkspace || (PNODE->workspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && !*PUSEACTIVE) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
// happens on reserved area
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
} else if (*PUSEACTIVE) {
if (g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow && g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) {
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
} else {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
}
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
} else
OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID);
@@ -241,6 +295,16 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
OPENINGON = getFirstNodeOnWorkspace(PNODE->workspaceID);
}
// first, check if OPENINGON isn't too big.
const auto PREDSIZEMAX = OPENINGON ? Vector2D(OPENINGON->size.x, OPENINGON->size.y) : PMONITOR->vecSize;
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
m_lDwindleNodesData.remove(*PNODE);
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(pWindow);
return;
}
// if it's the first, it's easy. Make it fullscreen.
if (!OPENINGON || OPENINGON->pWindow == pWindow) {
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
@@ -250,6 +314,28 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
return;
}
// if it's a group, add the window
if (OPENINGON->isGroupMember()) {
const auto PHEAD = OPENINGON->getGroupHead();
const auto PTAIL = PHEAD->pPreviousGroupMember;
PHEAD->pPreviousGroupMember = PNODE;
PTAIL->pNextGroupMember = PNODE;
PNODE->pNextGroupMember = PHEAD;
PNODE->pPreviousGroupMember = PTAIL;
PHEAD->setGroupFocusedNode(PNODE);
PNODE->position = PHEAD->position;
PNODE->size = PHEAD->size;
applyNodeDataToWindow(PNODE);
return;
}
// If it's not, get the node under our cursor
@@ -323,35 +409,66 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
OPENINGON->pParent = NEWPARENT;
PNODE->pParent = NEWPARENT;
if (OPENINGON->pGroupParent) {
// means we opened on a group
NEWPARENT->recalcSizePosRecursive();
// add the group deco
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
PNODE->pGroupParent = OPENINGON->pGroupParent;
PNODE->pGroupParent->groupMembers.push_back(PNODE);
PNODE->pGroupParent->groupMemberActive = PNODE->pGroupParent->groupMembers.size() - 1;
PNODE->pGroupParent->recalcSizePosRecursive();
} else {
NEWPARENT->recalcSizePosRecursive();
applyNodeDataToWindow(PNODE);
applyNodeDataToWindow(OPENINGON);
}
applyNodeDataToWindow(PNODE);
applyNodeDataToWindow(OPENINGON);
}
void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE)
if (!PNODE) {
Debug::log(ERR, "onWindowRemovedTiling node null?");
return;
}
// check if it was grouped
if (PNODE->isGroupMember()) {
// get shit
const auto PPREV = PNODE->pPreviousGroupMember;
const auto PNEXT = PNODE->pNextGroupMember;
PPREV->pNextGroupMember = PNEXT;
PNEXT->pPreviousGroupMember = PPREV;
if (PNODE->groupHead) {
PNEXT->groupHead = true;
PNEXT->pParent = PNODE->pParent;
if (PNODE->pParent) {
if (PNODE->pParent->children[0] == PNODE) {
PNODE->pParent->children[0] = PNEXT;
} else {
PNODE->pParent->children[1] = PNEXT;
}
}
PNEXT->position = PNODE->position;
PNEXT->size = PNODE->size;
applyNodeDataToWindow(PNEXT);
} else {
const auto PHEAD = PNODE->getGroupHead();
PNEXT->position = PHEAD->position;
PNEXT->size = PHEAD->size;
applyNodeDataToWindow(PNEXT);
}
PNEXT->setGroupFocusedNode(PNEXT);
PNEXT->pWindow->m_bHidden = false;
m_lDwindleNodesData.remove(*PNODE);
return;
}
const auto PPARENT = PNODE->pParent;
if (!PPARENT) {
Debug::log(LOG, "Removing last node (dwindle)");
m_lDwindleNodesData.remove(*PNODE);
return;
}
@@ -370,29 +487,6 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
}
}
// check if it was grouped
if (PNODE->pGroupParent) {
PNODE->pGroupParent->groupMembers.erase(PNODE->pGroupParent->groupMembers.begin() + PNODE->pGroupParent->groupMemberActive);
if ((long unsigned int)PNODE->pGroupParent->groupMemberActive >= PNODE->pGroupParent->groupMembers.size())
PNODE->pGroupParent->groupMemberActive = 0;
if (PNODE->pGroupParent->groupMembers.size() <= 1) {
PNODE->pGroupParent->isGroup = false;
PSIBLING->pGroupParent = nullptr;
PNODE->pGroupParent->groupMembers.clear();
PSIBLING->recalcSizePosRecursive();
} else {
PNODE->pGroupParent->recalcSizePosRecursive();
}
// if the parent is to be removed, remove the group
if (PPARENT == PNODE->pGroupParent) {
toggleWindowGroup(PPARENT->groupMembers[PPARENT->groupMemberActive]->pWindow);
}
}
PPARENT->valid = false;
PNODE->valid = false;
@@ -407,6 +501,10 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
if (!PMONITOR)
return; // ???
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
if (!PWORKSPACE)
@@ -432,17 +530,21 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
// massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
SDwindleNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = PWORKSPACE->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.position;
PFULLWINDOW->m_vSize = fakeNode.size;
if (!PFULLWINDOW) { // ????
PWORKSPACE->m_bHasFullscreenWindow = false;
} else {
SDwindleNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = PWORKSPACE->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.position;
PFULLWINDOW->m_vSize = fakeNode.size;
applyNodeDataToWindow(&fakeNode);
applyNodeDataToWindow(&fakeNode);
return;
return;
}
}
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace);
@@ -473,6 +575,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
return;
}
const auto PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
// get some data about our window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
@@ -504,11 +608,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
}
return;
@@ -523,11 +627,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
}
return;
@@ -542,14 +646,17 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
SIDECONTAINER->recalcSizePosRecursive();
TOPCONTAINER->recalcSizePosRecursive();
SIDECONTAINER->recalcSizePosRecursive(*PANIMATE == 0);
TOPCONTAINER->recalcSizePosRecursive(*PANIMATE == 0);
}
void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) {
if (!g_pCompositor->windowValidMapped(pWindow))
return;
if (!g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID))
return;
if (on == pWindow->m_bIsFullscreen)
return; // ignore
@@ -616,10 +723,6 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
g_pCompositor->moveWindowToTop(pWindow);
// we need to fix XWayland windows by sending them to NARNIA
// because otherwise they'd still be recieving mouse events
g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
recalculateMonitor(PMONITOR->ID);
}
@@ -632,6 +735,16 @@ void CHyprDwindleLayout::recalculateWindow(CWindow* pWindow) {
PNODE->recalcSizePosRecursive();
}
void addToDequeRecursive(std::deque<SDwindleNodeData*>* pDeque, std::deque<SDwindleNodeData*>* pParents, SDwindleNodeData* node) {
if (node->isNode) {
pParents->push_back(node);
addToDequeRecursive(pDeque, pParents, node->children[0]);
addToDequeRecursive(pDeque, pParents, node->children[1]);
} else {
pDeque->emplace_back(node);
}
}
void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
if (!g_pCompositor->windowValidMapped(pWindow))
return;
@@ -642,61 +755,115 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
if (!PNODE)
return; // reject
const auto PGROUPPARENT = PNODE->pGroupParent;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNODE->workspaceID);
if (PGROUPPARENT) {
// if there is a parent, release it
const auto INACTIVEBORDERCOL = CColor(g_pConfigManager->getInt("general:col.inactive_border"));
for (auto& node : PGROUPPARENT->groupMembers) {
node->pGroupParent = nullptr;
node->pWindow->m_cRealBorderColor.setValueAndWarp(INACTIVEBORDERCOL); // no anim here because they pop in
if (PWORKSPACE->m_bHasFullscreenWindow)
fullscreenRequestForWindow(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), FULLSCREEN_FULL, false);
for (auto& wd : node->pWindow->m_dWindowDecorations) {
wd->updateWindow(node->pWindow);
}
}
if (PNODE->isGroupMember()) {
// dissolve group
const auto PHEAD = PNODE->getGroupHead();
SDwindleNodeData* current = PNODE->pNextGroupMember;
PNODE->pWindow->m_bIsFloating = PHEAD->pWindow->m_bIsFloating;
std::deque<CWindow*> toAddWindows;
PGROUPPARENT->groupMembers.clear();
const auto PWINDOWNODE = PNODE->pWindow;
toAddWindows.push_back(PWINDOWNODE);
PGROUPPARENT->isGroup = false;
while (current != PNODE) {
const auto PWINDOW = current->pWindow;
current = current->pNextGroupMember;
PGROUPPARENT->recalcSizePosRecursive();
toAddWindows.push_back(PWINDOW);
if (g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
g_pCompositor->m_pLastWindow->m_cRealBorderColor = CColor(g_pConfigManager->getInt("general:col.active_border"));
} else {
// if there is no parent, let's make one
const auto PPARENT = PNODE->pParent;
if (!PPARENT)
return; // reject making group on single window
PPARENT->isGroup = true;
// recursively get all members
std::deque<SDwindleNodeData*> allChildren;
PPARENT->getAllChildrenRecursive(&allChildren);
PPARENT->groupMembers = allChildren;
const auto GROUPINACTIVEBORDERCOL = CColor(g_pConfigManager->getInt("dwinle:col.group_border"));
for (auto& c : PPARENT->groupMembers) {
c->pGroupParent = PPARENT;
c->pWindow->m_cRealBorderColor = GROUPINACTIVEBORDERCOL;
c->pWindow->m_dWindowDecorations.push_back(std::make_unique<CHyprGroupBarDecoration>(c->pWindow));
if (c->pWindow == g_pCompositor->m_pLastWindow)
c->pWindow->m_cRealBorderColor = CColor(g_pConfigManager->getInt("dwindle:col.group_border_active"));
PWINDOW->m_bHidden = false;
}
PPARENT->groupMemberActive = 0;
PHEAD->pPreviousGroupMember = nullptr;
PHEAD->pNextGroupMember = nullptr;
onWindowRemoved(PHEAD->pWindow);
PPARENT->recalcSizePosRecursive();
for (auto& pw : toAddWindows) {
const auto PNODE = getNodeFromWindow(pw);
if (PNODE)
m_lDwindleNodesData.remove(*PNODE);
pw->m_vPosition = Vector2D(-1000000, -1000000);
}
for (auto& pw : toAddWindows) {
onWindowCreated(pw);
}
recalculateMonitor(PWORKSPACE->m_iMonitorID);
} else {
// create group
if (!PNODE->pParent)
return;
PNODE->groupHead = true;
std::deque<SDwindleNodeData*> newGroupMembers;
std::deque<SDwindleNodeData*> nodesToRemove;
newGroupMembers.emplace_back(PNODE);
addToDequeRecursive(&newGroupMembers, &nodesToRemove, PNODE->pParent->children[0] == PNODE ? PNODE->pParent->children[1] : PNODE->pParent->children[0]);
for (auto& n : newGroupMembers) {
if (n->isGroupMember())
return; // reject nested groups
}
for (auto& nd : nodesToRemove) {
m_lDwindleNodesData.remove(*nd);
}
PNODE->position = PNODE->pParent->position;
PNODE->size = PNODE->pParent->size;
applyNodeDataToWindow(PNODE);
if (PNODE->pParent->pParent) {
if (PNODE->pParent->pParent->children[0] == PNODE->pParent) {
PNODE->pParent->pParent->children[0] = PNODE;
} else {
PNODE->pParent->pParent->children[1] = PNODE;
}
}
const auto PPARENT2 = PNODE->pParent->pParent;
m_lDwindleNodesData.remove(*PNODE->pParent);
PNODE->pParent = PPARENT2;
// now remove everyone but head from tree
// and set order
for (int i = 0; i < (int)newGroupMembers.size(); ++i) {
if (i != 0) {
newGroupMembers[i]->groupHead = false;
newGroupMembers[i]->pParent = PNODE->pParent;
}
const auto PREVMEMBER = i == 0 ? newGroupMembers[newGroupMembers.size() - 1] : newGroupMembers[i - 1];
const auto NEXTMEMBER = i == (int)newGroupMembers.size() - 1 ? newGroupMembers[0] : newGroupMembers[i + 1];
newGroupMembers[i]->pPreviousGroupMember = PREVMEMBER;
newGroupMembers[i]->pNextGroupMember = NEXTMEMBER;
}
// focus
PNODE->setGroupFocusedNode(PNODE);
}
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
g_pInputManager->refocus();
}
@@ -713,13 +880,13 @@ std::deque<CWindow*> CHyprDwindleLayout::getGroupMembers(CWindow* pWindow) {
if (!PNODE)
return result; // reject with empty
const auto PGROUPPARENT = PNODE->pGroupParent;
SDwindleNodeData* current = PNODE->pNextGroupMember;
if (!PGROUPPARENT)
return result; // reject with empty
result.push_back(pWindow);
for (auto& node : PGROUPPARENT->groupMembers) {
result.push_back(node->pWindow);
while (current != PNODE) {
result.push_back(current->pWindow);
current = current->pNextGroupMember;
}
return result;
@@ -731,33 +898,41 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE)
if (!PNODE || !PNODE->isGroupMember())
return; // reject
if (!PNODE->pGroupParent)
return; // reject
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNODE->workspaceID);
SDwindleNodeData* pNewNode;
if (forward)
PNODE->pGroupParent->groupMemberActive++;
pNewNode = PNODE->pNextGroupMember;
else
PNODE->pGroupParent->groupMemberActive--;
pNewNode = PNODE->pPreviousGroupMember;
if (PNODE->pGroupParent->groupMemberActive < 0)
PNODE->pGroupParent->groupMemberActive = PNODE->pGroupParent->groupMembers.size() - 1;
PNODE->setGroupFocusedNode(pNewNode);
if ((long unsigned int)PNODE->pGroupParent->groupMemberActive >= PNODE->pGroupParent->groupMembers.size())
PNODE->pGroupParent->groupMemberActive = 0;
pNewNode->position = PNODE->position;
pNewNode->size = PNODE->size;
PNODE->pGroupParent->recalcSizePosRecursive();
applyNodeDataToWindow(pNewNode);
for (auto& gm : PNODE->pGroupParent->groupMembers) {
for (auto& deco : gm->pWindow->m_dWindowDecorations) {
deco->updateWindow(gm->pWindow);
}
pNewNode->pWindow->m_vRealSize.warp();
pNewNode->pWindow->m_vRealPosition.warp();
g_pCompositor->focusWindow(pNewNode->pWindow);
pNewNode->pWindow->m_bIsFloating = PNODE->pWindow->m_bIsFloating;
if (PNODE->pWindow->m_bIsFullscreen) {
PNODE->pWindow->m_bHidden = false;
g_pCompositor->setWindowFullscreen(PNODE->pWindow, false, PWORKSPACE->m_efFullscreenMode);
PNODE->pWindow->m_bHidden = true;
g_pCompositor->setWindowFullscreen(pNewNode->pWindow, true, PWORKSPACE->m_efFullscreenMode);
pNewNode->pWindow->m_vRealSize.warp();
pNewNode->pWindow->m_vRealPosition.warp();
}
// focus
g_pCompositor->focusWindow(PNODE->pGroupParent->groupMembers[PNODE->pGroupParent->groupMemberActive]->pWindow);
}
SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow) {
@@ -769,7 +944,7 @@ SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow
if (!PNODE)
return hints; // left for the future, maybe floating funkiness
if (PNODE->pGroupParent) {
if (PNODE->isGroupMember()) {
hints.isBorderColor = true;
if (pWindow == g_pCompositor->m_pLastWindow)
@@ -894,4 +1069,4 @@ void CHyprDwindleLayout::onEnable() {
void CHyprDwindleLayout::onDisable() {
m_lDwindleNodesData.clear();
}
}

View File

@@ -18,10 +18,9 @@ struct SDwindleNodeData {
bool splitTop = false; // for preserve_split
bool isGroup = false;
int groupMemberActive = 0;
std::deque<SDwindleNodeData*> groupMembers;
SDwindleNodeData* pGroupParent = nullptr;
bool groupHead = false;
SDwindleNodeData* pNextGroupMember = nullptr;
SDwindleNodeData* pPreviousGroupMember = nullptr;
Vector2D position;
Vector2D size;
@@ -37,8 +36,12 @@ struct SDwindleNodeData {
return pWindow == rhs.pWindow && workspaceID == rhs.workspaceID && position == rhs.position && size == rhs.size && pParent == rhs.pParent && children[0] == rhs.children[0] && children[1] == rhs.children[1];
}
void recalcSizePosRecursive();
void recalcSizePosRecursive(bool force = false);
void getAllChildrenRecursive(std::deque<SDwindleNodeData*>*);
bool isGroupMember();
SDwindleNodeData* getGroupHead();
SDwindleNodeData* getGroupVisible();
void setGroupFocusedNode(SDwindleNodeData*);
CHyprDwindleLayout* layout = nullptr;
};
@@ -65,7 +68,7 @@ private:
std::list<SDwindleNodeData> m_lDwindleNodesData;
int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SDwindleNodeData*);
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
SDwindleNodeData* getNodeFromWindow(CWindow*);
SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
SDwindleNodeData* getMasterNodeOnWorkspace(const int&);

View File

@@ -6,6 +6,16 @@ void IHyprLayout::onWindowCreated(CWindow* pWindow) {
if (pWindow->m_bIsFloating) {
onWindowCreatedFloating(pWindow);
} else {
wlr_box desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f;
} else {
pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
}
onWindowCreatedTiling(pWindow);
}
}
@@ -36,7 +46,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height);
if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11) { // XDG windows should be fine. TODO: check for weird atoms?
if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { // XDG windows should be fine. TODO: check for weird atoms?
pWindow->m_bHidden = true;
return;
}
@@ -77,7 +87,6 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
if (pWindow->m_iX11Type != 2) {
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
g_pCompositor->moveWindowToTop(pWindow);
}
@@ -116,12 +125,14 @@ void IHyprLayout::onBeginDragWindow() {
changeWindowFloatingMode(DRAGGINGWINDOW);
DRAGGINGWINDOW->m_bIsFloating = true;
DRAGGINGWINDOW->m_bDraggingTiled = true;
DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize.goalv() / 2.f;
}
}
m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal();
m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.vec();
m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.vec();
m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goalv();
m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goalv();
m_vLastDragXY = m_vBeginDragXY;
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
@@ -156,6 +167,8 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y);
const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y);
const auto PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
if (abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f)
return;
@@ -166,16 +179,19 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (g_pInputManager->dragButton == BTN_LEFT) {
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA);
DRAGGINGWINDOW->updateWindowDecos();
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
} else {
if (DRAGGINGWINDOW->m_bIsFloating) {
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(m_vBeginDragSizeXY + DELTA);
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(Vector2D(std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().x, (double)20, (double)999999), std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().y, (double)20, (double)999999)));
DRAGGINGWINDOW->updateWindowDecos();
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW);
if (*PANIMATE) {
DRAGGINGWINDOW->m_vRealSize = Vector2D(std::clamp(m_vBeginDragSizeXY.x + DELTA.x, (double)20, (double)MAXSIZE.x), std::clamp(m_vBeginDragSizeXY.y + DELTA.y, (double)20, (double)MAXSIZE.y));
} else {
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(m_vBeginDragSizeXY + DELTA);
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(Vector2D(std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().x, (double)20, (double)MAXSIZE.x), std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().y, (double)20, (double)MAXSIZE.y)));
}
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
} else {
resizeActiveWindow(TICKDELTA, DRAGGINGWINDOW);
@@ -191,8 +207,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (PMONITOR) {
DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID;
DRAGGINGWINDOW->m_iWorkspaceID = PMONITOR->activeWorkspace;
DRAGGINGWINDOW->updateToplevel();
}
DRAGGINGWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
}
@@ -220,6 +240,8 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
// if the window is pseudo, update its size
pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec();
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
onWindowCreatedTiling(pWindow);
pWindow->m_vRealPosition.setValue(PSAVEDPOS);
@@ -235,17 +257,17 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
g_pCompositor->moveWindowToTop(pWindow);
const auto POS = pWindow->m_vRealPosition.goalv();
const auto SIZ = pWindow->m_vRealSize.goalv();
pWindow->m_vRealPosition.setValueAndWarp(POS + Vector2D(5, 5));
pWindow->m_vRealSize.setValueAndWarp(SIZ - Vector2D(10, 10));
pWindow->m_vRealPosition = POS;
pWindow->m_vRealSize = SIZ;
pWindow->m_vRealPosition = pWindow->m_vRealPosition.vec() + (pWindow->m_vRealSize.vec() - pWindow->m_vLastFloatingSize) / 2.f;
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
pWindow->m_sSpecialRenderData.rounding = true;
}
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
pWindow->updateToplevel();
}
void IHyprLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) {

View File

@@ -39,6 +39,8 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
static auto *const PNEWTOP = &g_pConfigManager->getConfigValuePtr("master:new_on_top")->intValue;
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back();
PNODE->workspaceID = pWindow->m_iWorkspaceID;
@@ -60,8 +62,26 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
PNODE->isMaster = true;
PNODE->percMaster = lastSplitPercent;
// first, check if it isn't too big.
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PMONITOR->vecSize.x * lastSplitPercent || MAXSIZE.y < PMONITOR->vecSize.y) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
m_lMasterNodesData.remove(*PNODE);
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(pWindow);
return;
}
} else {
PNODE->isMaster = false;
// first, check if it isn't too big.
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PMONITOR->vecSize.x * (1 - lastSplitPercent) || MAXSIZE.y < PMONITOR->vecSize.y * (1.f / (WINDOWSONWORKSPACE - 1))) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
m_lMasterNodesData.remove(*PNODE);
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(pWindow);
return;
}
}
// recalc
@@ -215,17 +235,19 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) {
PWINDOW->m_vRealPosition = calcPos;
PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos - Vector2D(BORDERSIZE, BORDERSIZE);
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
PWINDOW->updateWindowDecos();
PWINDOW->m_sSpecialRenderData.rounding = false;
PWINDOW->m_sSpecialRenderData.border = false;
return;
}
PWINDOW->m_sSpecialRenderData.rounding = true;
PWINDOW->m_sSpecialRenderData.border = true;
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN,
DISPLAYTOP ? GAPSOUT : GAPSIN);
@@ -250,6 +272,11 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
}
if (m_bForceWarps) {
PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealSize.warp();
}
PWINDOW->updateWindowDecos();
}
@@ -278,6 +305,8 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2)
return;
m_bForceWarps = true;
float delta = pixResize.x / PMONITOR->vecSize.x;
PMASTER->percMaster += delta;
@@ -285,12 +314,17 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
std::clamp(PMASTER->percMaster, 0.05f, 0.95f);
recalculateMonitor(PMONITOR->ID);
m_bForceWarps = false;
}
void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) {
if (!g_pCompositor->windowValidMapped(pWindow))
return;
if (!g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID))
return;
if (on == pWindow->m_bIsFullscreen)
return; // ignore
@@ -357,10 +391,6 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
g_pCompositor->moveWindowToTop(pWindow);
// we need to fix XWayland windows by sending them to NARNIA
// because otherwise they'd still be recieving mouse events
g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
recalculateMonitor(PMONITOR->ID);
}

View File

@@ -44,6 +44,8 @@ private:
std::list<SMasterNodeData> m_lMasterNodesData;
bool m_bForceWarps = false;
int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SMasterNodeData*);
SMasterNodeData* getNodeFromWindow(CWindow*);

View File

@@ -147,8 +147,8 @@ void CAnimationManager::tick() {
g_pHyprRenderer->damageBox(&WLRBOXPREV);
if (PWINDOW) {
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW);
} else if (PWORKSPACE) {
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_bHidden)
@@ -197,7 +197,7 @@ void CAnimationManager::tick() {
if (PDECO) {
const auto EXTENTS = PDECO->getWindowDecorationExtents();
wlr_box dmg = {PWINDOW->m_vRealPosition.vec().x + EXTENTS.topLeft.x, PWINDOW->m_vRealPosition.vec().y + EXTENTS.topLeft.y,
wlr_box dmg = {PWINDOW->m_vRealPosition.vec().x - EXTENTS.topLeft.x, PWINDOW->m_vRealPosition.vec().y - EXTENTS.topLeft.y,
PWINDOW->m_vRealSize.vec().x + EXTENTS.topLeft.x + EXTENTS.bottomRight.x, PWINDOW->m_vRealSize.vec().y + EXTENTS.topLeft.y + EXTENTS.bottomRight.y};
if (!*PSHADOWIGNOREWINDOW) {
@@ -257,21 +257,30 @@ bool CAnimationManager::deltazero(const CColor& a, const CColor& b) {
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
bool CAnimationManager::bezierExists(const std::string& bezier) {
for (auto&[bc, bz] : m_mBezierCurves) {
if (bc == bezier)
return true;
}
return false;
}
//
// Anims
//
//
void CAnimationManager::animationPopin(CWindow* pWindow, bool close) {
void CAnimationManager::animationPopin(CWindow* pWindow, bool close, float minPerc) {
const auto GOALPOS = pWindow->m_vRealPosition.goalv();
const auto GOALSIZE = pWindow->m_vRealSize.goalv();
if (!close) {
pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f);
pWindow->m_vRealSize.setValue(Vector2D(5, 5));
pWindow->m_vRealSize.setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}));
pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_vValue / 2.f);
} else {
pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f;
pWindow->m_vRealSize = Vector2D(5, 5);
pWindow->m_vRealSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y});
pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_vGoal / 2.f;
}
}
@@ -361,14 +370,72 @@ void CAnimationManager::onWindowPostCreateClose(CWindow* pWindow, bool close) {
}
} else {
// anim popin, fallback
animationPopin(pWindow, close);
float minPerc = 0.f;
if (pWindow->m_sAdditionalConfigData.animationStyle.find("%") != std::string::npos) {
try {
auto percstr = pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) {
; // oops
}
}
animationPopin(pWindow, close, minPerc / 100.f);
}
} else {
if (ANIMSTYLE == "slide") {
animationSlide(pWindow, "", close);
} else {
// anim popin, fallback
animationPopin(pWindow, close);
float minPerc = 0.f;
if (ANIMSTYLE.find("%") != 0) {
try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) {
; // oops
}
}
animationPopin(pWindow, close, minPerc / 100.f);
}
}
}
std::string CAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) {
if (config.find("window") == 0) {
if (style == "slide") {
return "";
} else if (style.find("popin") == 0) {
// try parsing
float minPerc = 0.f;
if (style.find("%") != std::string::npos) {
try {
auto percstr = style.substr(style.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) {
return "invalid minperc";
}
return "";
}
minPerc; // fix warning
return "";
}
return "unknown style";
} else if (config == "workspaces") {
if (style == "slide" || style == "slidevert" || style == "fade")
return "";
return "unknown style";
} else {
return "animation has no styles";
}
return "";
}

View File

@@ -18,6 +18,10 @@ public:
void onWindowPostCreateClose(CWindow*, bool close = false);
bool bezierExists(const std::string&);
std::string styleValidInConfigVar(const std::string&, const std::string&);
std::list<CAnimatedVariable*> m_lAnimatedVariables;
private:
@@ -31,7 +35,7 @@ private:
std::unordered_map<std::string, CBezierCurve> m_mBezierCurves;
// Anim stuff
void animationPopin(CWindow*, bool close = false);
void animationPopin(CWindow*, bool close = false, float minPerc = 0.f);
void animationSlide(CWindow*, std::string force = "", bool close = false);
};

View File

@@ -80,8 +80,8 @@ void CEventManager::startThread() {
eventQueueMutex.lock();
if (m_dQueuedEvents.empty()){ // if queue empty, sleep and ignore
std::this_thread::sleep_for(std::chrono::milliseconds(1));
eventQueueMutex.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}

View File

@@ -37,6 +37,8 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["layoutmsg"] = layoutmsg;
m_mDispatchers["toggleopaque"] = toggleOpaque;
m_mDispatchers["dpms"] = dpms;
m_mDispatchers["movewindowpixel"] = moveWindow;
m_mDispatchers["resizewindowpixel"] = resizeWindow;
m_tScrollTimer.reset();
}
@@ -93,6 +95,9 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
}
bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
if (pKeyboard->isVirtual)
return true;
const auto KEYCODE = e->keycode + 8; // Because to xkbcommon it's +8 from libinput
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(wlr_keyboard_from_input_device(pKeyboard->keyboard)->xkb_state, KEYCODE);
@@ -257,6 +262,11 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
// call the dispatcher
Debug::log(LOG, "Keybind triggered, calling dispatcher (%d, %s, %d)", modmask, key.c_str(), keysym);
DISPATCHER->second(k.arg);
if (k.handler == "submap") {
found = true; // don't process keybinds on submap change.
break;
}
}
if (k.repeat) {
@@ -405,14 +415,7 @@ void CKeybindManager::spawn(std::string args) {
}
void CKeybindManager::killActive(std::string args) {
if (g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow)) {
g_pXWaylandManager->sendCloseWindow(g_pCompositor->m_pLastWindow);
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastWindow = nullptr;
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // post an activewindow event to empty, as we are currently unfocused
}
g_pCompositor->focusWindow(g_pCompositor->windowFromCursor());
g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow);
}
void CKeybindManager::clearKeybinds() {
@@ -466,7 +469,7 @@ void CKeybindManager::changeworkspace(std::string args) {
}
// remove constraints
g_pCompositor->m_sSeat.mouse->constraintActive = false;
g_pInputManager->unconstrainMouse();
// if it exists, we warp to it
if (g_pCompositor->getWorkspaceByID(workspaceToChangeTo)) {
@@ -487,13 +490,6 @@ void CKeybindManager::changeworkspace(std::string args) {
else
PMONITOR->specialWorkspaceOpen = true;
// we need to move XWayland windows to narnia or otherwise they will still process our cursor and shit
// and that'd be annoying as hell
g_pCompositor->fixXWaylandWindowsOnWorkspace(OLDWORKSPACEID);
// and fix on the new workspace
g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
// here and only here begin anim. we don't want to anim visible workspaces on other monitors.
// check if anim left or right
const auto ANIMTOLEFT = workspaceToChangeTo > OLDWORKSPACEID;
@@ -562,10 +558,6 @@ void CKeybindManager::changeworkspace(std::string args) {
else
PMONITOR->specialWorkspaceOpen = true;
// we need to move XWayland windows to narnia or otherwise they will still process our cursor and shit
// and that'd be annoying as hell
g_pCompositor->fixXWaylandWindowsOnWorkspace(OLDWORKSPACE);
// set active and deactivate all other
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACE->m_pWlrHandle);
PWORKSPACE->setActive(true);
@@ -592,7 +584,15 @@ void CKeybindManager::fullscreenActive(std::string args) {
}
void CKeybindManager::moveActiveToWorkspace(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
CWindow* PWINDOW = nullptr;
if (args.contains(',')) {
PWINDOW = g_pCompositor->getWindowByRegex(args.substr(args.find_last_of(',') + 1));
args = args.substr(0, args.find_last_of(','));
} else {
PWINDOW = g_pCompositor->m_pLastWindow;
}
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
@@ -668,11 +668,27 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
}
g_pInputManager->refocus();
PWINDOW->updateToplevel();
}
void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
// hacky, but works lol
CWindow* PWINDOW = nullptr;
const auto ORIGINALARGS = args;
if (args.contains(',')) {
PWINDOW = g_pCompositor->getWindowByRegex(args.substr(args.find_last_of(',') + 1));
args = args.substr(0, args.find_last_of(','));
} else {
PWINDOW = g_pCompositor->m_pLastWindow;
}
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
int workspaceToMoveTo = 0;
std::string workspaceName = "";
@@ -683,14 +699,9 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
return;
}
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (workspaceToMoveTo == PMONITOR->activeWorkspace)
if (workspaceToMoveTo == PWINDOW->m_iWorkspaceID)
return;
// may be null until later!
@@ -706,7 +717,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
g_pEventManager->m_bIgnoreEvents = true;
moveActiveToWorkspace(args);
moveActiveToWorkspace(ORIGINALARGS);
PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceToMoveTo);
@@ -738,13 +749,27 @@ void CKeybindManager::moveFocusTo(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
if (!PLASTWINDOW)
return;
// remove constraints
g_pCompositor->m_sSeat.mouse->constraintActive = false;
g_pInputManager->unconstrainMouse();
auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) {
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f;
g_pCompositor->warpCursorTo(middle);
if (PLASTWINDOW->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && PLASTWINDOW->m_bIsFullscreen) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PLASTWINDOW->m_iWorkspaceID);
const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
g_pCompositor->setWindowFullscreen(PLASTWINDOW, false, FULLSCREEN_FULL);
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE);
} else {
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f;
g_pCompositor->warpCursorTo(middle);
}
};
if (!g_pCompositor->windowValidMapped(PLASTWINDOW)) {
@@ -801,7 +826,7 @@ void CKeybindManager::moveActiveTo(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PLASTWINDOW))
if (!g_pCompositor->windowValidMapped(PLASTWINDOW) || PLASTWINDOW->m_bIsFullscreen)
return;
const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
@@ -1132,120 +1157,90 @@ void CKeybindManager::forceRendererReload(std::string args) {
}
void CKeybindManager::resizeActive(std::string args) {
if (!args.contains(' '))
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return;
std::string x = args.substr(0, args.find_first_of(' '));
std::string y = args.substr(args.find_first_of(' ') + 1);
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealSize.goalv());
if (x == "exact") {
std::string newX = y.substr(0, y.find_first_of(' '));
std::string newY = y.substr(y.find_first_of(' ') + 1);
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - g_pCompositor->m_pLastWindow->m_vRealSize.goalv());
if (!isNumber(newX) || !isNumber(newY)) {
Debug::log(ERR, "resizeTiledWindow: exact args not numbers");
return;
}
const int X = std::stoi(newX);
const int Y = std::stoi(newY);
if (X < 10 || Y < 10) {
Debug::log(ERR, "resizeTiledWindow: exact args cannot be < 10");
return;
}
// calc the delta
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return; // ignore
const auto PWINDOW = g_pCompositor->m_pLastWindow;
const int DX = X - PWINDOW->m_vRealSize.goalv().x;
const int DY = Y - PWINDOW->m_vRealSize.goalv().y;
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(Vector2D(DX, DY));
return;
}
if (!isNumber(x) || !isNumber(y)) {
Debug::log(ERR, "resizeTiledWindow: args not numbers");
return;
}
const int X = std::stoi(x);
const int Y = std::stoi(y);
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(Vector2D(X, Y));
if (g_pCompositor->m_pLastWindow->m_vRealSize.goalv().x > 1 && g_pCompositor->m_pLastWindow->m_vRealSize.goalv().y > 1)
g_pCompositor->m_pLastWindow->m_bHidden = false;
}
void CKeybindManager::moveActive(std::string args) {
if (!args.contains(' '))
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return;
std::string x = args.substr(0, args.find_first_of(' '));
std::string y = args.substr(args.find_first_of(' ') + 1);
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealPosition.goalv());
if (x == "exact") {
std::string newX = y.substr(0, y.find_first_of(' '));
std::string newY = y.substr(y.find_first_of(' ') + 1);
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - g_pCompositor->m_pLastWindow->m_vRealPosition.goalv());
}
if (!isNumber(newX) || !isNumber(newY)) {
Debug::log(ERR, "moveActive: exact args not numbers");
return;
}
void CKeybindManager::moveWindow(std::string args) {
const int X = std::stoi(newX);
const int Y = std::stoi(newY);
const auto WINDOWREGEX = args.substr(args.find_first_of(',') + 1);
const auto MOVECMD = args.substr(0, args.find_first_of(','));
if (X < 0 || Y < 0) {
Debug::log(ERR, "moveActive: exact args cannot be < 0");
return;
}
// calc the delta
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return; // ignore
const auto PWINDOW = g_pCompositor->m_pLastWindow;
const int DX = X - PWINDOW->m_vRealPosition.goalv().x;
const int DY = Y - PWINDOW->m_vRealPosition.goalv().y;
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(Vector2D(DX, DY));
const auto PWINDOW = g_pCompositor->getWindowByRegex(WINDOWREGEX);
if (!PWINDOW) {
Debug::log(ERR, "moveWindow: no window");
return;
}
if (!isNumber(x) || !isNumber(y)) {
Debug::log(ERR, "moveActive: args not numbers");
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goalv());
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PWINDOW->m_vRealPosition.goalv(), PWINDOW);
}
void CKeybindManager::resizeWindow(std::string args) {
const auto WINDOWREGEX = args.substr(args.find_first_of(',') + 1);
const auto MOVECMD = args.substr(0, args.find_first_of(','));
const auto PWINDOW = g_pCompositor->getWindowByRegex(WINDOWREGEX);
if (!PWINDOW) {
Debug::log(ERR, "resizeWindow: no window");
return;
}
const int X = std::stoi(x);
const int Y = std::stoi(y);
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goalv());
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(Vector2D(X, Y));
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize.goalv(), PWINDOW);
if (PWINDOW->m_vRealSize.goalv().x > 1 && PWINDOW->m_vRealSize.goalv().y > 1)
PWINDOW->m_bHidden = false;
}
void CKeybindManager::circleNext(std::string arg) {
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID);
auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) {
if (PWINDOWTOCHANGETO == g_pCompositor->m_pLastWindow || !PWINDOWTOCHANGETO)
return;
if (PWORKSPACE->m_bHasFullscreenWindow)
return;
if (g_pCompositor->m_pLastWindow->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsFullscreen) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID);
const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
g_pCompositor->setWindowFullscreen(g_pCompositor->m_pLastWindow, false, FULLSCREEN_FULL);
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE);
} else {
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f;
g_pCompositor->warpCursorTo(middle);
}
};
if (arg == "last" || arg == "l" || arg == "prev" || arg == "p")
g_pCompositor->focusWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow));
switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow));
else
g_pCompositor->focusWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow));
const auto MIDPOINT = g_pCompositor->m_pLastWindow->m_vRealPosition.goalv() + g_pCompositor->m_pLastWindow->m_vRealSize.goalv() / 2.f;
g_pCompositor->warpCursorTo(MIDPOINT);
switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow));
}
void CKeybindManager::focusWindow(std::string regexp) {
@@ -1305,6 +1300,9 @@ void CKeybindManager::pass(std::string regexp) {
// pass all mf shit
wlr_seat_keyboard_notify_enter(g_pCompositor->m_sSeat.seat, g_pXWaylandManager->getWindowSurface(PWINDOW), KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers);
wlr_keyboard_modifiers kbmods = {g_pInputManager->accumulateModsFromAllKBs(), 0, 0, 0};
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &kbmods);
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_PRESSED);
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_RELEASED);

View File

@@ -94,6 +94,8 @@ private:
static void forceRendererReload(std::string);
static void resizeActive(std::string);
static void moveActive(std::string);
static void moveWindow(std::string);
static void resizeWindow(std::string);
static void circleNext(std::string);
static void focusWindow(std::string);
static void setSubmap(std::string);

View File

@@ -120,9 +120,9 @@ void CHyprXWaylandManager::sendCloseWindow(CWindow* pWindow) {
}
}
void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, const Vector2D& size) {
void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, const Vector2D& size, bool force) {
if ((pWindow->m_vReportedSize == size && pWindow->m_vRealPosition.vec() == pWindow->m_vReportedPosition) || (pWindow->m_vReportedSize == size && !pWindow->m_bIsX11))
if (!force && ((pWindow->m_vReportedSize == size && pWindow->m_vRealPosition.vec() == pWindow->m_vReportedPosition) || (pWindow->m_vReportedSize == size && !pWindow->m_bIsX11)))
return;
pWindow->m_vReportedPosition = pWindow->m_vRealPosition.vec();
@@ -155,8 +155,11 @@ bool CHyprXWaylandManager::shouldBeFloated(CWindow* pWindow) {
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
{
pWindow->m_bNoInitialFocus = true;
return true;
if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
pWindow->m_bX11ShouldntFocus = true;
pWindow->m_bNoInitialFocus = true;
return true;
}
if (pWindow->m_uSurface.xwayland->role) {
@@ -230,4 +233,22 @@ void CHyprXWaylandManager::setWindowFullscreen(CWindow* pWindow, bool fullscreen
if (pWindow->m_phForeignToplevel)
wlr_foreign_toplevel_handle_v1_set_fullscreen(pWindow->m_phForeignToplevel, fullscreen);
}
}
Vector2D CHyprXWaylandManager::getMaxSizeForWindow(CWindow* pWindow) {
if (!g_pCompositor->windowValidMapped(pWindow))
return Vector2D(99999, 99999);
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel))
return Vector2D(99999, 99999);
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height)
: Vector2D(pWindow->m_uSurface.xdg->toplevel->current.max_width, pWindow->m_uSurface.xdg->toplevel->current.max_height);
if (MAXSIZE.x < 5)
MAXSIZE.x = 99999;
if (MAXSIZE.y < 5)
MAXSIZE.y = 99999;
return MAXSIZE;
}

View File

@@ -17,13 +17,14 @@ public:
std::string getTitle(CWindow*);
std::string getAppIDClass(CWindow*);
void sendCloseWindow(CWindow*);
void setWindowSize(CWindow*, const Vector2D&);
void setWindowSize(CWindow*, const Vector2D&, bool force = false);
void setWindowStyleTiled(CWindow*, uint32_t);
void setWindowFullscreen(CWindow*, bool);
wlr_surface* surfaceAt(CWindow*, const Vector2D&, Vector2D&);
bool shouldBeFloated(CWindow*);
void moveXWaylandWindow(CWindow*, const Vector2D&);
void checkBorders(CWindow*);
Vector2D getMaxSizeForWindow(CWindow*);
};
inline std::unique_ptr<CHyprXWaylandManager> g_pXWaylandManager;

View File

@@ -29,7 +29,9 @@ void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) {
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
static auto* const PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue;
static auto *const PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue;
static auto *const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
static auto *const PHOGFOCUS = &g_pConfigManager->getConfigValuePtr("misc:layers_hog_keyboard_focus")->intValue;
if (!g_pCompositor->m_bReadyToProcess)
return;
@@ -67,7 +69,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
if (!CONSTRAINTWINDOW) {
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr;
unconstrainMouse();
} else {
// Native Wayland apps know how 2 constrain themselves.
// XWayland, we just have to accept them. Might cause issues, but thats XWayland for ya.
@@ -123,7 +125,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
ACTIVEWORKSPACE->setActive(true);
// event
g_pEventManager->postEvent(SHyprIPCEvent{"activemon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName});
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName});
}
Vector2D surfaceCoords;
@@ -180,11 +182,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen))
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
}
} else
} else {
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (!pFoundWindow && refocus)
pFoundWindow = g_pCompositor->getFirstWindowOnWorkspace(PWORKSPACE->m_iID);
// TODO: this causes crashes, sometimes. ???
// if (refocus && !pFoundWindow) {
// pFoundWindow = g_pCompositor->getFirstWindowOnWorkspace(PMONITOR->activeWorkspace);
// }
}
if (pFoundWindow) {
if (!pFoundWindow->m_bIsX11) {
@@ -212,9 +217,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat);
if (refocus) { // if we are forcing a refocus, and we don't find a surface, clear the kb focus too!
g_pCompositor->focusSurface(nullptr);
g_pCompositor->m_pLastWindow = nullptr;
g_pCompositor->focusWindow(nullptr);
}
return;
@@ -233,11 +236,21 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
surfaceLocal = mouseCoords - surfacePos + Vector2D(geom.x, geom.y);
}
bool allowKeyboardRefocus = true;
if (*PHOGFOCUS && !refocus && g_pCompositor->m_pLastFocus) {
const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
if (PLS && PLS->layerSurface->current.keyboard_interactive) {
allowKeyboardRefocus = false;
}
}
if (pFoundWindow) {
if (*PFOLLOWMOUSE != 1 && !refocus) {
if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating)) {
// enter if change floating style
if (*PFOLLOWMOUSE != 3)
if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} else if (*PFOLLOWMOUSE == 2) {
@@ -249,14 +262,22 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
if (*PFOLLOWONDND && m_sDrag.dragIcon) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
return; // don't enter any new surfaces
} else {
if (*PFOLLOWMOUSE != 3)
if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
}
} else if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3)
g_pCompositor->focusSurface(foundSurface);
} else {
if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3 && allowKeyboardRefocus) {
g_pCompositor->focusSurface(foundSurface);
g_pCompositor->m_pLastWindow = nullptr; // reset last window as we have a full focus on a LS
}
}
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
@@ -315,7 +336,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
m_ecbClickBehavior = CLICKMODE_KILL;
// remove constraints
g_pCompositor->m_sSeat.mouse->constraintActive = false;
g_pInputManager->unconstrainMouse();
refocus();
// set cursor
@@ -428,10 +449,19 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard");
if (m_pActiveKeyboard)
m_pActiveKeyboard->active = false;
PNEWKEYBOARD->hyprListener_keyboardKeymap.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.keymap, [&](void* owner, void* data) {
const auto PKEYBOARD = (SKeyboard*)owner;
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", PKEYBOARD->name + "," +getActiveLayoutForKeyboard(PKEYBOARD)}, true); // force as this should ALWAYS be sent
}, PNEWKEYBOARD, "Keyboard");
disableAllKeyboards(false);
m_pActiveKeyboard = PNEWKEYBOARD;
PNEWKEYBOARD->active = true;
applyConfigToKeyboard(PNEWKEYBOARD);
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(keyboard));
@@ -439,6 +469,41 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
Debug::log(LOG, "New keyboard created, pointers Hypr: %x and WLR: %x", PNEWKEYBOARD, keyboard);
}
void CInputManager::newVirtualKeyboard(wlr_input_device* keyboard) {
const auto PNEWKEYBOARD = &m_lKeyboards.emplace_back();
PNEWKEYBOARD->keyboard = keyboard;
PNEWKEYBOARD->isVirtual = true;
try {
PNEWKEYBOARD->name = std::string(keyboard->name);
} catch (std::exception& e) {
Debug::log(ERR, "Keyboard had no name???"); // logic error
}
PNEWKEYBOARD->hyprListener_keyboardMod.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.modifiers, &Events::listener_keyboardMod, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardKeymap.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.keymap, [&](void* owner, void* data) {
const auto PKEYBOARD = (SKeyboard*)owner;
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", PKEYBOARD->name + "," +getActiveLayoutForKeyboard(PKEYBOARD)}, true); // force as this should ALWAYS be sent
}, PNEWKEYBOARD, "Keyboard");
disableAllKeyboards(true);
m_pActiveKeyboard = PNEWKEYBOARD;
PNEWKEYBOARD->active = true;
applyConfigToKeyboard(PNEWKEYBOARD);
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(keyboard));
Debug::log(LOG, "New virtual keyboard created, pointers Hypr: %x and WLR: %x", PNEWKEYBOARD, keyboard);
}
void CInputManager::setKeyboardLayout() {
for (auto& k : m_lKeyboards)
applyConfigToKeyboard(&k);
@@ -462,6 +527,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
const auto NUMLOCKON = HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "numlock_by_default") : g_pConfigManager->getInt("input:numlock_by_default");
const auto FILEPATH = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_file") : g_pConfigManager->getString("input:kb_file");
const auto RULES = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_rules") : g_pConfigManager->getString("input:kb_rules");
const auto MODEL = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_model") : g_pConfigManager->getString("input:kb_model");
const auto LAYOUT = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_layout") : g_pConfigManager->getString("input:kb_layout");
@@ -469,7 +535,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
const auto OPTIONS = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_options") : g_pConfigManager->getString("input:kb_options");
try {
if (NUMLOCKON == pKeyboard->numlockOn && REPEATDELAY == pKeyboard->repeatDelay && REPEATRATE == pKeyboard->repeatRate && RULES != "" && RULES == pKeyboard->currentRules.rules && MODEL == pKeyboard->currentRules.model && LAYOUT == pKeyboard->currentRules.layout && VARIANT == pKeyboard->currentRules.variant && OPTIONS == pKeyboard->currentRules.options) {
if (NUMLOCKON == pKeyboard->numlockOn && REPEATDELAY == pKeyboard->repeatDelay && REPEATRATE == pKeyboard->repeatRate && RULES != "" && RULES == pKeyboard->currentRules.rules && MODEL == pKeyboard->currentRules.model && LAYOUT == pKeyboard->currentRules.layout && VARIANT == pKeyboard->currentRules.variant && OPTIONS == pKeyboard->currentRules.options && FILEPATH == pKeyboard->xkbFilePath) {
Debug::log(LOG, "Not applying config to keyboard, it did not change.");
return;
}
@@ -483,6 +549,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
pKeyboard->repeatDelay = REPEATDELAY;
pKeyboard->repeatRate = REPEATRATE;
pKeyboard->numlockOn = NUMLOCKON;
pKeyboard->xkbFilePath = FILEPATH.c_str();
xkb_rule_names rules = {
.rules = RULES.c_str(),
@@ -506,9 +573,25 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
Debug::log(LOG, "Attempting to create a keymap for layout %s with variant %s (rules: %s, model: %s, options: %s)", rules.layout, rules.variant, rules.rules, rules.model, rules.options);
auto KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_keymap * KEYMAP = NULL;
if (!FILEPATH.empty()) {
auto path = absolutePath(FILEPATH, g_pConfigManager->configCurrentPath);
if (!std::filesystem::exists(path)) {
Debug::log(ERR, "input:kb_file= file doesnt exist");
} else {
KEYMAP = xkb_keymap_new_from_file(CONTEXT, fopen(path.c_str(), "r"), XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
}
if (!KEYMAP) {
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
if (!KEYMAP) {
g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS + ", layout: " + LAYOUT + " )");
Debug::log(ERR, "Keyboard layout %s with variant %s (rules: %s, model: %s, options: %s) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, rules.options);
memset(&rules, 0, sizeof(rules));
@@ -540,6 +623,8 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
xkb_keymap_unref(KEYMAP);
xkb_context_unref(CONTEXT);
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->name + "," +getActiveLayoutForKeyboard(pKeyboard)}, true); // force as this should ALWAYS be sent
Debug::log(LOG, "Set the keyboard layout to %s and variant to %s for keyboard \"%s\"", rules.layout, rules.variant, pKeyboard->keyboard->name);
}
@@ -661,7 +746,7 @@ void CInputManager::destroyMouse(wlr_input_device* mouse) {
g_pCompositor->m_sSeat.mouse = m_lMice.size() > 0 ? &m_lMice.front() : nullptr;
if (g_pCompositor->m_sSeat.mouse)
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr;
unconstrainMouse();
}
void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
@@ -670,14 +755,37 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
if (passEvent) {
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e->time_msec, e->keycode, e->state);
const auto PIMEGRAB = m_sIMERelay.getIMEKeyboardGrab(pKeyboard);
if (PIMEGRAB && PIMEGRAB->pWlrKbGrab && PIMEGRAB->pWlrKbGrab->input_method) {
wlr_input_method_keyboard_grab_v2_set_keyboard(PIMEGRAB->pWlrKbGrab, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_input_method_keyboard_grab_v2_send_key(PIMEGRAB->pWlrKbGrab, e->time_msec, e->keycode, e->state);
} else {
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e->time_msec, e->keycode, e->state);
}
}
}
void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers);
const auto PIMEGRAB = m_sIMERelay.getIMEKeyboardGrab(pKeyboard);
if (PIMEGRAB && PIMEGRAB->pWlrKbGrab && PIMEGRAB->pWlrKbGrab->input_method) {
wlr_input_method_keyboard_grab_v2_set_keyboard(PIMEGRAB->pWlrKbGrab, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_input_method_keyboard_grab_v2_send_modifiers(PIMEGRAB->pWlrKbGrab, &wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers);
} else {
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers);
}
const auto PWLRKB = wlr_keyboard_from_input_device(pKeyboard->keyboard);
if (PWLRKB->modifiers.group != pKeyboard->activeLayout) {
pKeyboard->activeLayout = PWLRKB->modifiers.group;
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->name + "," + getActiveLayoutForKeyboard(pKeyboard)}, true); // force as this should ALWAYS be sent
}
}
void CInputManager::refocus() {
@@ -685,16 +793,16 @@ void CInputManager::refocus() {
}
void CInputManager::updateDragIcon() {
if (!g_pInputManager->m_sDrag.dragIcon)
if (!m_sDrag.dragIcon)
return;
switch (g_pInputManager->m_sDrag.dragIcon->drag->grab_type) {
switch (m_sDrag.dragIcon->drag->grab_type) {
case WLR_DRAG_GRAB_KEYBOARD:
break;
case WLR_DRAG_GRAB_KEYBOARD_POINTER: {
wlr_box box = {g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4};
wlr_box box = {m_sDrag.pos.x - 2, m_sDrag.pos.y - 2, m_sDrag.dragIcon->surface->current.width + 4, m_sDrag.dragIcon->surface->current.height + 4};
g_pHyprRenderer->damageBox(&box);
g_pInputManager->m_sDrag.pos = g_pInputManager->getMouseCoordsInternal();
m_sDrag.pos = getMouseCoordsInternal();
break;
}
default:
@@ -773,6 +881,29 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
Debug::log(LOG, "Constrained mouse to %x", pMouse->currentConstraint);
}
void CInputManager::unconstrainMouse() {
if (!g_pCompositor->m_sSeat.mouse->currentConstraint)
return;
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
if (CONSTRAINTWINDOW) {
if (CONSTRAINTWINDOW->m_bIsX11) {
wlr_xwayland_surface_activate(CONSTRAINTWINDOW->m_uSurface.xwayland, false);
} else {
wlr_xdg_toplevel_set_activated(CONSTRAINTWINDOW->m_uSurface.xdg->toplevel, false);
}
}
wlr_pointer_constraint_v1_send_deactivated(g_pCompositor->m_sSeat.mouse->currentConstraint);
g_pCompositor->m_sSeat.mouse->constraintActive = false;
// TODO: its better to somehow detect the workspace...
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr;
g_pCompositor->m_sSeat.mouse->hyprListener_commitConstraint.removeCallback();
}
void Events::listener_commitConstraint(void* owner, void* data) {
//g_pInputManager->recheckConstraint((SMouse*)owner);
}
@@ -807,3 +938,32 @@ uint32_t CInputManager::accumulateModsFromAllKBs() {
return finalMask;
}
std::string CInputManager::getActiveLayoutForKeyboard(SKeyboard* pKeyboard) {
const auto WLRKB = wlr_keyboard_from_input_device(pKeyboard->keyboard);
const auto KEYMAP = WLRKB->keymap;
const auto STATE = WLRKB->xkb_state;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE)) {
const auto LAYOUTNAME = xkb_keymap_layout_get_name(KEYMAP, i);
if (LAYOUTNAME)
return std::string(LAYOUTNAME);
return "error";
}
}
return "none";
}
void CInputManager::disableAllKeyboards(bool virt) {
for (auto& k : m_lKeyboards) {
if (k.isVirtual != virt)
continue;
k.active = false;
}
}

View File

@@ -5,12 +5,18 @@
#include "../../helpers/WLClasses.hpp"
#include "../../Window.hpp"
#include "../../helpers/Timer.hpp"
#include "InputMethodRelay.hpp"
enum eClickBehaviorMode {
CLICKMODE_DEFAULT = 0,
CLICKMODE_KILL
};
struct STouchData {
CWindow* touchFocusWindow = nullptr;
Vector2D touchSurfaceOrigin;
};
class CInputManager {
public:
@@ -22,12 +28,15 @@ public:
void onKeyboardMod(void*, SKeyboard*);
void newKeyboard(wlr_input_device*);
void newVirtualKeyboard(wlr_input_device*);
void newMouse(wlr_input_device*, bool virt = false);
void destroyKeyboard(SKeyboard*);
void destroyMouse(wlr_input_device*);
void constrainMouse(SMouse*, wlr_pointer_constraint_v1*);
void recheckConstraint(SMouse*);
void unconstrainMouse();
std::string getActiveLayoutForKeyboard(SKeyboard*);
Vector2D getMouseCoordsInternal();
void refocus();
@@ -42,6 +51,11 @@ public:
eClickBehaviorMode getClickMode();
void processMouseRequest(wlr_seat_pointer_request_set_cursor_event*);
void onTouchDown(wlr_touch_down_event*);
void onTouchUp(wlr_touch_up_event*);
void onTouchMove(wlr_touch_motion_event*);
STouchData m_sTouchData;
// for dragging floating windows
CWindow* currentlyDraggedWindow = nullptr;
@@ -77,9 +91,13 @@ public:
CTimer m_tmrLastCursorMovement;
CInputMethodRelay m_sIMERelay;
// for shared mods
uint32_t accumulateModsFromAllKBs();
CWindow* m_pFollowOnDnDBegin = nullptr;
private:
// for click behavior override
@@ -89,6 +107,8 @@ private:
void processMouseDownNormal(wlr_pointer_button_event* e);
void processMouseDownKill(wlr_pointer_button_event* e);
void disableAllKeyboards(bool virt = false);
uint32_t m_uiCapabilities = 0;
void mouseMoveUnified(uint32_t, bool refocus = false);

View File

@@ -0,0 +1,447 @@
#include "InputMethodRelay.hpp"
#include "InputManager.hpp"
#include "../../Compositor.hpp"
CInputMethodRelay::CInputMethodRelay() {
}
void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) {
if (m_pWLRIME) {
Debug::log(ERR, "Cannot register 2 IMEs at once!");
wlr_input_method_v2_send_unavailable(pIME);
return;
}
m_pWLRIME = pIME;
hyprListener_IMECommit.initCallback(&m_pWLRIME->events.commit, [&](void* owner, void* data) {
const auto PTI = getFocusedTextInput();
const auto PIMR = (CInputMethodRelay*)owner;
if (!PTI) {
Debug::log(LOG, "No focused TextInput on IME Commit");
return;
}
if (PIMR->m_pWLRIME->current.preedit.text) {
wlr_text_input_v3_send_preedit_string(PTI->pWlrInput, PIMR->m_pWLRIME->current.preedit.text, PIMR->m_pWLRIME->current.preedit.cursor_begin, PIMR->m_pWLRIME->current.preedit.cursor_end);
}
if (PIMR->m_pWLRIME->current.commit_text) {
wlr_text_input_v3_send_commit_string(PTI->pWlrInput, PIMR->m_pWLRIME->current.commit_text);
}
if (PIMR->m_pWLRIME->current.delete_.before_length || PIMR->m_pWLRIME->current.delete_.after_length) {
wlr_text_input_v3_send_delete_surrounding_text(PTI->pWlrInput, PIMR->m_pWLRIME->current.delete_.before_length, PIMR->m_pWLRIME->current.delete_.after_length);
}
wlr_text_input_v3_send_done(PTI->pWlrInput);
}, this, "IMERelay");
hyprListener_IMEDestroy.initCallback(&m_pWLRIME->events.destroy, [&](void* owner, void* data) {
m_pWLRIME = nullptr;
hyprListener_IMEDestroy.removeCallback();
hyprListener_IMECommit.removeCallback();
hyprListener_IMEGrab.removeCallback();
hyprListener_IMENewPopup.removeCallback();
m_pKeyboardGrab.reset(nullptr);
const auto PTI = getFocusedTextInput();
Debug::log(LOG, "IME Destroy");
if (PTI) {
setPendingSurface(PTI, PTI->pWlrInput->focused_surface);
wlr_text_input_v3_send_leave(PTI->pWlrInput);
}
}, this, "IMERelay");
hyprListener_IMEGrab.initCallback(&m_pWLRIME->events.grab_keyboard, [&](void* owner, void* data) {
Debug::log(LOG, "IME TextInput Keyboard Grab new");
m_pKeyboardGrab.reset(nullptr);
m_pKeyboardGrab = std::make_unique<SIMEKbGrab>();
m_pKeyboardGrab->pKeyboard = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat);
const auto PKBGRAB = (wlr_input_method_keyboard_grab_v2*)data;
m_pKeyboardGrab->pWlrKbGrab = PKBGRAB;
wlr_input_method_keyboard_grab_v2_set_keyboard(m_pKeyboardGrab->pWlrKbGrab, m_pKeyboardGrab->pKeyboard);
m_pKeyboardGrab->hyprListener_grabDestroy.initCallback(&PKBGRAB->events.destroy, [&](void* owner, void* data) {
m_pKeyboardGrab->hyprListener_grabDestroy.removeCallback();
Debug::log(LOG, "IME TextInput Keyboard Grab destroy");
if (m_pKeyboardGrab->pKeyboard) {
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &m_pKeyboardGrab->pKeyboard->modifiers);
}
m_pKeyboardGrab.reset(nullptr);
}, m_pKeyboardGrab.get(), "IME Keyboard Grab");
}, this, "IMERelay");
hyprListener_IMENewPopup.initCallback(&m_pWLRIME->events.new_popup_surface, [&](void* owner, void* data) {
const auto PNEWPOPUP = &m_lIMEPopups.emplace_back();
PNEWPOPUP->pSurface = (wlr_input_popup_surface_v2*)data;
PNEWPOPUP->hyprListener_commitPopup.initCallback(&PNEWPOPUP->pSurface->surface->events.commit, &Events::listener_commitInputPopup, PNEWPOPUP, "IME Popup");
PNEWPOPUP->hyprListener_mapPopup.initCallback(&PNEWPOPUP->pSurface->events.map, &Events::listener_mapInputPopup, PNEWPOPUP, "IME Popup");
PNEWPOPUP->hyprListener_unmapPopup.initCallback(&PNEWPOPUP->pSurface->events.unmap, &Events::listener_unmapInputPopup, PNEWPOPUP, "IME Popup");
PNEWPOPUP->hyprListener_destroyPopup.initCallback(&PNEWPOPUP->pSurface->events.destroy, &Events::listener_destroyInputPopup, PNEWPOPUP, "IME Popup");
Debug::log(LOG, "New input popup");
}, this, "IMERelay");
const auto PTI = getFocusableTextInput();
if (PTI) {
wlr_text_input_v3_send_enter(PTI->pWlrInput, PTI->pPendingSurface);
setPendingSurface(PTI, nullptr);
}
}
void CInputMethodRelay::updateInputPopup(SIMEPopup* pPopup) {
if (!pPopup->pSurface->mapped)
return;
const auto PFOCUSEDTI = getFocusedTextInput();
if (!PFOCUSEDTI || !PFOCUSEDTI->pWlrInput->focused_surface)
return;
bool cursorRect = PFOCUSEDTI->pWlrInput->current.features & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE;
const auto PFOCUSEDSURFACE = PFOCUSEDTI->pWlrInput->focused_surface;
auto cursorBox = PFOCUSEDTI->pWlrInput->current.cursor_rectangle;
Vector2D parentPos;
Vector2D parentSize;
if (wlr_surface_is_layer_surface(PFOCUSEDSURFACE)) {
const auto PLS = g_pCompositor->getLayerSurfaceFromWlr(wlr_layer_surface_v1_from_wlr_surface(PFOCUSEDSURFACE));
if (PLS) {
parentPos = Vector2D(PLS->geometry.x, PLS->geometry.y) + g_pCompositor->getMonitorFromID(PLS->monitorID)->vecPosition;
parentSize = Vector2D(PLS->geometry.width, PLS->geometry.height);
}
} else {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(PFOCUSEDSURFACE);
if (PWINDOW) {
parentPos = PWINDOW->m_vRealPosition.goalv();
parentSize = PWINDOW->m_vRealSize.goalv();
}
}
if (!cursorRect) {
cursorBox = {0, 0, (int)parentSize.x, (int)parentSize.y};
}
// todo: anti-overflow
wlr_box finalBox = cursorBox;
pPopup->x = finalBox.x;
pPopup->y = finalBox.y + finalBox.height;
pPopup->realX = finalBox.x + parentPos.x;
pPopup->realY = finalBox.y + parentPos.y + finalBox.height;
wlr_input_popup_surface_v2_send_text_input_rectangle(pPopup->pSurface, &finalBox);
damagePopup(pPopup);
}
void CInputMethodRelay::setIMEPopupFocus(SIMEPopup* pPopup, wlr_surface* pSurface) {
updateInputPopup(pPopup);
}
void Events::listener_mapInputPopup(void* owner, void* data) {
const auto PPOPUP = (SIMEPopup*)owner;
Debug::log(LOG, "Mapped an IME Popup");
g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP);
}
void Events::listener_unmapInputPopup(void* owner, void* data) {
const auto PPOPUP = (SIMEPopup*)owner;
Debug::log(LOG, "Unmapped an IME Popup");
g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP);
}
void Events::listener_destroyInputPopup(void* owner, void* data) {
const auto PPOPUP = (SIMEPopup*)owner;
Debug::log(LOG, "Removed an IME Popup");
PPOPUP->hyprListener_commitPopup.removeCallback();
PPOPUP->hyprListener_destroyPopup.removeCallback();
PPOPUP->hyprListener_focusedSurfaceUnmap.removeCallback();
PPOPUP->hyprListener_mapPopup.removeCallback();
PPOPUP->hyprListener_unmapPopup.removeCallback();
g_pInputManager->m_sIMERelay.removePopup(PPOPUP);
}
void Events::listener_commitInputPopup(void* owner, void* data) {
const auto PPOPUP = (SIMEPopup*)owner;
g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP);
}
void CInputMethodRelay::removePopup(SIMEPopup* pPopup) {
m_lIMEPopups.remove(*pPopup);
}
void CInputMethodRelay::damagePopup(SIMEPopup* pPopup) {
if (!pPopup->pSurface->mapped)
return;
const auto PFOCUSEDTI = getFocusedTextInput();
if (!PFOCUSEDTI || !PFOCUSEDTI->pWlrInput->focused_surface)
return;
Vector2D parentPos;
const auto PFOCUSEDSURFACE = PFOCUSEDTI->pWlrInput->focused_surface;
if (wlr_surface_is_layer_surface(PFOCUSEDSURFACE)) {
const auto PLS = g_pCompositor->getLayerSurfaceFromWlr(wlr_layer_surface_v1_from_wlr_surface(PFOCUSEDSURFACE));
if (PLS) {
parentPos = Vector2D(PLS->geometry.x, PLS->geometry.y) + g_pCompositor->getMonitorFromID(PLS->monitorID)->vecPosition;
}
} else {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(PFOCUSEDSURFACE);
if (PWINDOW) {
parentPos = PWINDOW->m_vRealPosition.goalv();
}
}
g_pHyprRenderer->damageSurface(pPopup->pSurface->surface, parentPos.x + pPopup->x, parentPos.y + pPopup->y);
}
SIMEKbGrab* CInputMethodRelay::getIMEKeyboardGrab(SKeyboard* pKeyboard) {
if (!m_pWLRIME)
return nullptr;
if (!m_pKeyboardGrab.get())
return nullptr;
const auto VIRTKB = wlr_input_device_get_virtual_keyboard(pKeyboard->keyboard);
if (VIRTKB && (wl_resource_get_client(VIRTKB->resource) == wl_resource_get_client(m_pKeyboardGrab->pWlrKbGrab->resource)))
return nullptr;
if (wlr_keyboard_from_input_device(pKeyboard->keyboard) != m_pKeyboardGrab->pKeyboard)
return nullptr;
return m_pKeyboardGrab.get();
}
STextInput* CInputMethodRelay::getFocusedTextInput() {
for (auto& ti : m_lTextInputs) {
if (ti.pWlrInput->focused_surface) {
return &ti;
}
}
return nullptr;
}
STextInput* CInputMethodRelay::getFocusableTextInput() {
for (auto& ti : m_lTextInputs) {
if (ti.pPendingSurface) {
return &ti;
}
}
return nullptr;
}
void CInputMethodRelay::onNewTextInput(wlr_text_input_v3* pInput) {
createNewTextInput(pInput);
}
void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
const auto PTEXTINPUT = &m_lTextInputs.emplace_back();
PTEXTINPUT->pWlrInput = pInput;
PTEXTINPUT->hyprListener_textInputEnable.initCallback(&pInput->events.enable, [](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(ERR, "Enabling TextInput on no IME!");
return;
}
Debug::log(LOG, "Enable TextInput");
wlr_input_method_v2_send_activate(g_pInputManager->m_sIMERelay.m_pWLRIME);
g_pInputManager->m_sIMERelay.commitIMEState(PINPUT->pWlrInput);
}, PTEXTINPUT, "textInput");
PTEXTINPUT->hyprListener_textInputCommit.initCallback(&pInput->events.commit, [](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(ERR, "Committing TextInput on no IME!");
return;
}
if (!PINPUT->pWlrInput->current_enabled) {
Debug::log(ERR, "Disabled TextInput commit?");
return;
}
g_pInputManager->m_sIMERelay.commitIMEState(PINPUT->pWlrInput);
}, PTEXTINPUT, "textInput");
PTEXTINPUT->hyprListener_textInputDisable.initCallback(&pInput->events.disable, [](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(ERR, "Disabling TextInput on no IME!");
return;
}
Debug::log(LOG, "Disable TextInput");
wlr_input_method_v2_send_deactivate(g_pInputManager->m_sIMERelay.m_pWLRIME);
g_pInputManager->m_sIMERelay.commitIMEState(PINPUT->pWlrInput);
}, PTEXTINPUT, "textInput");
PTEXTINPUT->hyprListener_textInputDestroy.initCallback(&pInput->events.destroy, [](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(ERR, "Disabling TextInput on no IME!");
return;
}
if (PINPUT->pWlrInput->current_enabled) {
wlr_input_method_v2_send_deactivate(g_pInputManager->m_sIMERelay.m_pWLRIME);
g_pInputManager->m_sIMERelay.commitIMEState(PINPUT->pWlrInput);
}
g_pInputManager->m_sIMERelay.setPendingSurface(PINPUT, nullptr);
PINPUT->hyprListener_textInputCommit.removeCallback();
PINPUT->hyprListener_textInputDestroy.removeCallback();
PINPUT->hyprListener_textInputDisable.removeCallback();
PINPUT->hyprListener_textInputEnable.removeCallback();
g_pInputManager->m_sIMERelay.removeTextInput(PINPUT->pWlrInput);
}, PTEXTINPUT, "textInput");
}
void CInputMethodRelay::removeTextInput(wlr_text_input_v3* pInput) {
m_lTextInputs.remove_if([&](const auto& other) { return other.pWlrInput == pInput; });
}
void CInputMethodRelay::commitIMEState(wlr_text_input_v3* pInput) {
if (!m_pWLRIME)
return;
if (pInput->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT)
wlr_input_method_v2_send_surrounding_text(m_pWLRIME, pInput->current.surrounding.text, pInput->current.surrounding.cursor, pInput->current.surrounding.anchor);
wlr_input_method_v2_send_text_change_cause(m_pWLRIME, pInput->current.text_change_cause);
if (pInput->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE)
wlr_input_method_v2_send_content_type(m_pWLRIME, pInput->current.content_type.hint, pInput->current.content_type.purpose);
for (auto& p : m_lIMEPopups) {
updateInputPopup(&p);
}
wlr_input_method_v2_send_done(m_pWLRIME);
}
void CInputMethodRelay::onKeyboardFocus(wlr_surface* pSurface) {
if (!m_pWLRIME)
return;
for (auto& ti : m_lTextInputs) {
if (ti.pPendingSurface) {
if (pSurface != ti.pPendingSurface)
setPendingSurface(&ti, nullptr);
} else if (ti.pWlrInput->focused_surface) {
if (pSurface != ti.pWlrInput->focused_surface) {
wlr_input_method_v2_send_deactivate(m_pWLRIME);
commitIMEState(ti.pWlrInput);
wlr_text_input_v3_send_leave(ti.pWlrInput);
} else {
continue;
}
}
if (pSurface && wl_resource_get_client(ti.pWlrInput->resource) == wl_resource_get_client(pSurface->resource)) {
if (m_pWLRIME) {
wlr_text_input_v3_send_enter(ti.pWlrInput, pSurface);
} else {
setPendingSurface(&ti, pSurface);
}
}
}
}
void CInputMethodRelay::setPendingSurface(STextInput* pInput, wlr_surface* pSurface) {
pInput->pPendingSurface = pSurface;
if (pSurface) {
pInput->hyprListener_pendingSurfaceDestroy.initCallback(&pSurface->events.destroy, [](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
PINPUT->pPendingSurface = nullptr;
PINPUT->hyprListener_pendingSurfaceDestroy.removeCallback();
}, pInput, "TextInput");
} else {
pInput->hyprListener_pendingSurfaceDestroy.removeCallback();
}
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include "../../defines.hpp"
#include "../../helpers/WLClasses.hpp"
class CInputMethodRelay {
public:
CInputMethodRelay();
void onNewIME(wlr_input_method_v2*);
void onNewTextInput(wlr_text_input_v3*);
wlr_input_method_v2* m_pWLRIME = nullptr;
void commitIMEState(wlr_text_input_v3*);
void removeTextInput(wlr_text_input_v3*);
void onKeyboardFocus(wlr_surface*);
STextInput* getFocusedTextInput();
STextInput* getFocusableTextInput();
void setPendingSurface(STextInput*, wlr_surface*);
SIMEKbGrab* getIMEKeyboardGrab(SKeyboard*);
void setIMEPopupFocus(SIMEPopup*, wlr_surface*);
void updateInputPopup(SIMEPopup*);
void damagePopup(SIMEPopup*);
void removePopup(SIMEPopup*);
private:
std::unique_ptr<SIMEKbGrab> m_pKeyboardGrab;
std::list<STextInput> m_lTextInputs;
std::list<SIMEPopup> m_lIMEPopups;
DYNLISTENER(textInputNew);
DYNLISTENER(IMECommit);
DYNLISTENER(IMEDestroy);
DYNLISTENER(IMEGrab);
DYNLISTENER(IMENewPopup);
void createNewTextInput(wlr_text_input_v3*);
friend class CHyprRenderer;
};

View File

@@ -79,7 +79,7 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(m_sActiveSwipe.pMonitor->vecSize.x, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f);
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr;
g_pInputManager->unconstrainMouse();
Debug::log(LOG, "Ended swipe to the left");
} else {
@@ -95,11 +95,13 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-m_sActiveSwipe.pMonitor->vecSize.x, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f);
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr;
g_pInputManager->unconstrainMouse();
Debug::log(LOG, "Ended swipe to the right");
}
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
PWORKSPACEL->m_bForceRendering = false;
PWORKSPACER->m_bForceRendering = false;
m_sActiveSwipe.pWorkspaceBegin->m_bForceRendering = false;
@@ -141,11 +143,13 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
PWORKSPACE->m_bForceRendering = true;
PWORKSPACE->m_fAlpha.setValueAndWarp(255.f);
if (workspaceIDLeft != workspaceIDRight) {
const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight);
PWORKSPACER->m_bForceRendering = false;
PWORKSPACER->m_fAlpha.setValueAndWarp(0.f);
}
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x - m_sActiveSwipe.pMonitor->vecSize.x, 0));
@@ -161,11 +165,13 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight);
PWORKSPACE->m_bForceRendering = true;
PWORKSPACE->m_fAlpha.setValueAndWarp(255.f);
if (workspaceIDLeft != workspaceIDRight) {
const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
PWORKSPACEL->m_bForceRendering = false;
PWORKSPACEL->m_fAlpha.setValueAndWarp(0.f);
}
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x + m_sActiveSwipe.pMonitor->vecSize.x, 0));

View File

@@ -0,0 +1,45 @@
#include "InputManager.hpp"
#include "../../Compositor.hpp"
void CInputManager::onTouchDown(wlr_touch_down_event* e) {
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, g_pCompositor->m_pLastMonitor->vecPosition.x + e->x * g_pCompositor->m_pLastMonitor->vecSize.x, g_pCompositor->m_pLastMonitor->vecPosition.y + e->y * g_pCompositor->m_pLastMonitor->vecSize.y);
refocus();
m_sTouchData.touchFocusWindow = nullptr;
if (g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow)) {
Vector2D local;
if (g_pCompositor->m_pLastWindow->m_bIsX11) {
local = g_pInputManager->getMouseCoordsInternal() - g_pCompositor->m_pLastWindow->m_vRealPosition.goalv();
} else {
g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), g_pCompositor->m_pLastWindow, local);
}
m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local;
wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, g_pCompositor->m_pLastFocus, e->time_msec, e->touch_id, local.x, local.y);
m_sTouchData.touchFocusWindow = g_pCompositor->m_pLastWindow;
}
}
void CInputManager::onTouchUp(wlr_touch_up_event* e){
if (m_sTouchData.touchFocusWindow) {
wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id);
}
}
void CInputManager::onTouchMove(wlr_touch_motion_event* e){
if (g_pCompositor->windowValidMapped(m_sTouchData.touchFocusWindow)) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
}
}

View File

@@ -23,110 +23,6 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!");
#endif
// Init shaders
GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC);
m_shQUAD.program = prog;
m_shQUAD.proj = glGetUniformLocation(prog, "proj");
m_shQUAD.color = glGetUniformLocation(prog, "color");
m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos");
m_shQUAD.texAttrib = glGetAttribLocation(prog, "texcoord");
m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft");
m_shQUAD.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize");
m_shQUAD.radius = glGetUniformLocation(prog, "radius");
m_shQUAD.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA);
m_shRGBA.program = prog;
m_shRGBA.proj = glGetUniformLocation(prog, "proj");
m_shRGBA.tex = glGetUniformLocation(prog, "tex");
m_shRGBA.alpha = glGetUniformLocation(prog, "alpha");
m_shRGBA.texAttrib = glGetAttribLocation(prog, "texcoord");
m_shRGBA.posAttrib = glGetAttribLocation(prog, "pos");
m_shRGBA.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft");
m_shRGBA.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize");
m_shRGBA.radius = glGetUniformLocation(prog, "radius");
m_shRGBA.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBX);
m_shRGBX.program = prog;
m_shRGBX.tex = glGetUniformLocation(prog, "tex");
m_shRGBX.proj = glGetUniformLocation(prog, "proj");
m_shRGBX.alpha = glGetUniformLocation(prog, "alpha");
m_shRGBX.texAttrib = glGetAttribLocation(prog, "texcoord");
m_shRGBX.posAttrib = glGetAttribLocation(prog, "pos");
m_shRGBX.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft");
m_shRGBX.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize");
m_shRGBX.radius = glGetUniformLocation(prog, "radius");
m_shRGBX.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
prog = createProgram(TEXVERTSRC, TEXFRAGSRCEXT);
m_shEXT.program = prog;
m_shEXT.tex = glGetUniformLocation(prog, "tex");
m_shEXT.proj = glGetUniformLocation(prog, "proj");
m_shEXT.alpha = glGetUniformLocation(prog, "alpha");
m_shEXT.posAttrib = glGetAttribLocation(prog, "pos");
m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord");
m_shEXT.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft");
m_shEXT.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize");
m_shEXT.radius = glGetUniformLocation(prog, "radius");
m_shEXT.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
prog = createProgram(TEXVERTSRC, FRAGBLUR1);
m_shBLUR1.program = prog;
m_shBLUR1.tex = glGetUniformLocation(prog, "tex");
m_shBLUR1.alpha = glGetUniformLocation(prog, "alpha");
m_shBLUR1.proj = glGetUniformLocation(prog, "proj");
m_shBLUR1.posAttrib = glGetAttribLocation(prog, "pos");
m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord");
m_shBLUR1.radius = glGetUniformLocation(prog, "radius");
m_shBLUR1.halfpixel = glGetUniformLocation(prog, "halfpixel");
prog = createProgram(TEXVERTSRC, FRAGBLUR2);
m_shBLUR2.program = prog;
m_shBLUR2.tex = glGetUniformLocation(prog, "tex");
m_shBLUR2.alpha = glGetUniformLocation(prog, "alpha");
m_shBLUR2.proj = glGetUniformLocation(prog, "proj");
m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos");
m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord");
m_shBLUR2.radius = glGetUniformLocation(prog, "radius");
m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel");
prog = createProgram(QUADVERTSRC, FRAGSHADOW);
m_shSHADOW.program = prog;
m_shSHADOW.proj = glGetUniformLocation(prog, "proj");
m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos");
m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord");
m_shSHADOW.topLeft = glGetUniformLocation(prog, "topLeft");
m_shSHADOW.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_shSHADOW.fullSize = glGetUniformLocation(prog, "fullSize");
m_shSHADOW.radius = glGetUniformLocation(prog, "radius");
m_shSHADOW.range = glGetUniformLocation(prog, "range");
m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower");
m_shSHADOW.color = glGetUniformLocation(prog, "color");
prog = createProgram(QUADVERTSRC, FRAGBORDER1);
m_shBORDER1.program = prog;
m_shBORDER1.proj = glGetUniformLocation(prog, "proj");
m_shBORDER1.thick = glGetUniformLocation(prog, "thick");
m_shBORDER1.posAttrib = glGetAttribLocation(prog, "pos");
m_shBORDER1.texAttrib = glGetAttribLocation(prog, "texcoord");
m_shBORDER1.topLeft = glGetUniformLocation(prog, "topLeft");
m_shBORDER1.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_shBORDER1.fullSize = glGetUniformLocation(prog, "fullSize");
m_shBORDER1.radius = glGetUniformLocation(prog, "radius");
m_shBORDER1.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
m_shBORDER1.color = glGetUniformLocation(prog, "color");
Debug::log(LOG, "Shaders initialized successfully.");
// End shaders
pixman_region32_init(&m_rOriginalDamageRegion);
@@ -180,6 +76,10 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) {
void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool fake) {
m_RenderData.pMonitor = pMonitor;
if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL)) {
eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL));
}
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
@@ -206,6 +106,9 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool
createBGTextureForMonitor(pMonitor);
}
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
initShaders();
// bind the primary Hypr Framebuffer
m_RenderData.pCurrentMonData->primaryFB.bind();
@@ -236,6 +139,112 @@ void CHyprOpenGLImpl::end() {
m_iWLROutputFb = 0;
}
void CHyprOpenGLImpl::initShaders() {
GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC);
m_RenderData.pCurrentMonData->m_shQUAD.program = prog;
m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color");
m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shQUAD.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shQUAD.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shQUAD.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA);
m_RenderData.pCurrentMonData->m_shRGBA.program = prog;
m_RenderData.pCurrentMonData->m_shRGBA.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shRGBA.tex = glGetUniformLocation(prog, "tex");
m_RenderData.pCurrentMonData->m_shRGBA.alpha = glGetUniformLocation(prog, "alpha");
m_RenderData.pCurrentMonData->m_shRGBA.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shRGBA.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shRGBA.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_RenderData.pCurrentMonData->m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shRGBA.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shRGBA.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shRGBA.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBX);
m_RenderData.pCurrentMonData->m_shRGBX.program = prog;
m_RenderData.pCurrentMonData->m_shRGBX.tex = glGetUniformLocation(prog, "tex");
m_RenderData.pCurrentMonData->m_shRGBX.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shRGBX.alpha = glGetUniformLocation(prog, "alpha");
m_RenderData.pCurrentMonData->m_shRGBX.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shRGBX.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shRGBX.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_RenderData.pCurrentMonData->m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shRGBX.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shRGBX.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shRGBX.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
prog = createProgram(TEXVERTSRC, TEXFRAGSRCEXT);
m_RenderData.pCurrentMonData->m_shEXT.program = prog;
m_RenderData.pCurrentMonData->m_shEXT.tex = glGetUniformLocation(prog, "tex");
m_RenderData.pCurrentMonData->m_shEXT.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shEXT.alpha = glGetUniformLocation(prog, "alpha");
m_RenderData.pCurrentMonData->m_shEXT.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shEXT.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_RenderData.pCurrentMonData->m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shEXT.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shEXT.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shEXT.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
prog = createProgram(TEXVERTSRC, FRAGBLUR1);
m_RenderData.pCurrentMonData->m_shBLUR1.program = prog;
m_RenderData.pCurrentMonData->m_shBLUR1.tex = glGetUniformLocation(prog, "tex");
m_RenderData.pCurrentMonData->m_shBLUR1.alpha = glGetUniformLocation(prog, "alpha");
m_RenderData.pCurrentMonData->m_shBLUR1.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shBLUR1.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shBLUR1.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel = glGetUniformLocation(prog, "halfpixel");
prog = createProgram(TEXVERTSRC, FRAGBLUR2);
m_RenderData.pCurrentMonData->m_shBLUR2.program = prog;
m_RenderData.pCurrentMonData->m_shBLUR2.tex = glGetUniformLocation(prog, "tex");
m_RenderData.pCurrentMonData->m_shBLUR2.alpha = glGetUniformLocation(prog, "alpha");
m_RenderData.pCurrentMonData->m_shBLUR2.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shBLUR2.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel");
prog = createProgram(QUADVERTSRC, FRAGSHADOW);
m_RenderData.pCurrentMonData->m_shSHADOW.program = prog;
m_RenderData.pCurrentMonData->m_shSHADOW.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shSHADOW.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shSHADOW.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shSHADOW.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shSHADOW.range = glGetUniformLocation(prog, "range");
m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower");
m_RenderData.pCurrentMonData->m_shSHADOW.color = glGetUniformLocation(prog, "color");
prog = createProgram(QUADVERTSRC, FRAGBORDER1);
m_RenderData.pCurrentMonData->m_shBORDER1.program = prog;
m_RenderData.pCurrentMonData->m_shBORDER1.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shBORDER1.thick = glGetUniformLocation(prog, "thick");
m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shBORDER1.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shBORDER1.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
m_RenderData.pCurrentMonData->m_shBORDER1.color = glGetUniformLocation(prog, "color");
m_RenderData.pCurrentMonData->m_bShadersInitialized = true;
Debug::log(LOG, "Shaders initialized successfully.");
}
void CHyprOpenGLImpl::clear(const CColor& color) {
RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!");
@@ -311,10 +320,10 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_shQUAD.program);
glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program);
glUniformMatrix3fv(m_shQUAD.proj, 1, GL_FALSE, glMatrix);
glUniform4f(m_shQUAD.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix);
glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
const auto TOPLEFT = Vector2D(round, round);
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round);
@@ -323,17 +332,17 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
// Rounded corners
glUniform2f(m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shQUAD.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shQUAD.radius, round);
glUniform1i(m_shQUAD.primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0));
glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.radius, round);
glUniform1i(m_RenderData.pCurrentMonData->m_shQUAD.primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0));
glVertexAttribPointer(m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_shQUAD.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shQUAD.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shQUAD.posAttrib);
glEnableVertexAttribArray(m_shQUAD.texAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.texAttrib);
if (pixman_region32_not_empty(damage)) {
PIXMAN_DAMAGE_FOREACH(damage) {
@@ -343,8 +352,8 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm
}
}
glDisableVertexAttribArray(m_shQUAD.posAttrib);
glDisableVertexAttribArray(m_shQUAD.texAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.texAttrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
@@ -385,13 +394,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
switch (tex.m_iType) {
case TEXTURE_RGBA:
shader = &m_shRGBA;
shader = &m_RenderData.pCurrentMonData->m_shRGBA;
break;
case TEXTURE_RGBX:
shader = &m_shRGBX;
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
break;
case TEXTURE_EXTERNAL:
shader = &m_shEXT;
shader = &m_RenderData.pCurrentMonData->m_shEXT;
break;
default:
RASSERT(false, "tex.m_iTarget unsupported!");
@@ -510,10 +519,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
// prep two shaders
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
glUniform1f(pShader->radius, *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a
if (pShader == &m_shBLUR1)
glUniform2f(m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f));
if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1)
glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f));
else
glUniform2f(m_shBLUR2.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f));
glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f));
glUniform1i(pShader->tex, 0);
glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
@@ -550,17 +559,17 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
pixman_region32_init(&tempDamage);
wlr_region_scale(&tempDamage, &damage, 1.f / 2.f); // when DOWNscaling, we make the region twice as small because it's the TARGET
drawPass(&m_shBLUR1, &tempDamage);
drawPass(&m_RenderData.pCurrentMonData->m_shBLUR1, &tempDamage);
// and draw
for (int i = 1; i < *PBLURPASSES; ++i) {
wlr_region_scale(&tempDamage, &damage, 1.f / (1 << (i + 1)));
drawPass(&m_shBLUR1, &tempDamage); // down
drawPass(&m_RenderData.pCurrentMonData->m_shBLUR1, &tempDamage); // down
}
for (int i = *PBLURPASSES - 1; i >= 0; --i) {
wlr_region_scale(&tempDamage, &damage, 1.f / (1 << i)); // when upsampling we make the region twice as big
drawPass(&m_shBLUR2, &tempDamage); // up
drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up
}
// finish
@@ -741,6 +750,23 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto *const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
if (*PBORDERSIZE < 1)
return;
if (round < 1) {
// zero rounding, just lines
wlr_box borderbox = {box->x - *PBORDERSIZE, box->y - *PBORDERSIZE, *PBORDERSIZE, box->height + 2 * *PBORDERSIZE};
renderRect(&borderbox, col, 0); // left
borderbox = {box->x, box->y - (int)*PBORDERSIZE, box->width + (int)*PBORDERSIZE, (int)*PBORDERSIZE};
renderRect(&borderbox, col, 0); // top
borderbox = {box->x + box->width, box->y, (int)*PBORDERSIZE, box->height + (int)*PBORDERSIZE};
renderRect(&borderbox, col, 0); // right
borderbox = {box->x, box->y + box->height, box->width, (int)*PBORDERSIZE};
renderRect(&borderbox, col, 0); // bottom
return;
}
// adjust box
box->x -= *PBORDERSIZE;
box->y -= *PBORDERSIZE;
@@ -761,27 +787,27 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_shBORDER1.program);
glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program);
glUniformMatrix3fv(m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
glUniform4f(m_shBORDER1.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
glUniform4f(m_RenderData.pCurrentMonData->m_shBORDER1.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
const auto TOPLEFT = Vector2D(round, round);
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round);
const auto FULLSIZE = Vector2D(box->width, box->height);
glUniform2f(m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shBORDER1.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shBORDER1.radius, round);
glUniform1f(m_shBORDER1.thick, *PBORDERSIZE);
glUniform1i(m_shBORDER1.primitiveMultisample, *PMULTISAMPLE);
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round);
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, *PBORDERSIZE);
glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample, *PMULTISAMPLE);
glVertexAttribPointer(m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shBORDER1.posAttrib);
glEnableVertexAttribArray(m_shBORDER1.texAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
@@ -791,8 +817,8 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
}
}
glDisableVertexAttribArray(m_shBORDER1.posAttrib);
glDisableVertexAttribArray(m_shBORDER1.texAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
@@ -1004,28 +1030,28 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_shSHADOW.program);
glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program);
glUniformMatrix3fv(m_shSHADOW.proj, 1, GL_FALSE, glMatrix);
glUniform4f(m_shSHADOW.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix);
glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a);
const auto TOPLEFT = Vector2D(range + round, range + round);
const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round));
const auto FULLSIZE = Vector2D(box->width, box->height);
// Rounded corners
glUniform2f(m_shSHADOW.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shSHADOW.radius, range + round);
glUniform1f(m_shSHADOW.range, range);
glUniform1f(m_shSHADOW.shadowPower, SHADOWPOWER);
glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.radius, range + round);
glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.range, range);
glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower, SHADOWPOWER);
glVertexAttribPointer(m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shSHADOW.posAttrib);
glEnableVertexAttribArray(m_shSHADOW.texAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
@@ -1035,8 +1061,8 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
}
}
glDisableVertexAttribArray(m_shSHADOW.posAttrib);
glDisableVertexAttribArray(m_shSHADOW.texAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
@@ -1081,10 +1107,10 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
// get the adequate tex
std::string texPath = "/usr/share/hyprland/wall_";
Vector2D textureSize;
if (pMonitor->vecTransformedSize.x > 7000) {
if (pMonitor->vecTransformedSize.x > 3850) {
textureSize = Vector2D(7680, 4320);
texPath += "8K.png";
} else if (pMonitor->vecTransformedSize.x > 3000) {
} else if (pMonitor->vecTransformedSize.x > 1930) {
textureSize = Vector2D(3840, 2160);
texPath += "4K.png";
} else {
@@ -1105,8 +1131,8 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
// copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
glBindTexture(GL_TEXTURE_2D, PTEX->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#ifndef GLES2
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);

View File

@@ -42,6 +42,18 @@ struct SMonitorRenderData {
bool blurFBDirty = true;
wlr_box backgroundTexBox;
// Shaders
bool m_bShadersInitialized = false;
CShader m_shQUAD;
CShader m_shRGBA;
CShader m_shRGBX;
CShader m_shEXT;
CShader m_shBLUR1;
CShader m_shBLUR2;
CShader m_shSHADOW;
CShader m_shBORDER1;
//
};
struct SCurrentRenderData {
@@ -114,20 +126,10 @@ private:
bool m_bFakeFrame = false;
bool m_bEndFrame = false;
// Shaders
CShader m_shQUAD;
CShader m_shRGBA;
CShader m_shRGBX;
CShader m_shEXT;
CShader m_shBLUR1;
CShader m_shBLUR2;
CShader m_shSHADOW;
CShader m_shBORDER1;
//
GLuint createProgram(const std::string&, const std::string&);
GLuint compileShader(const GLuint&, std::string);
void createBGTextureForMonitor(CMonitor*);
void initShaders();
// returns the out FB, can be either Mirror or MirrorSwap
CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage);

View File

@@ -32,10 +32,9 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
scaleBox(&windowBox, RDATA->output->scale);
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
static auto *const PBORDERTHICK = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? *PROUNDING : RDATA->rounding;
rounding += *PBORDERTHICK;
rounding *= RDATA->output->scale;
if (RDATA->surface && surface == RDATA->surface) {
if (wlr_surface_is_xwayland_surface(surface) && !wlr_xwayland_surface_from_wlr_surface(surface)->has_alpha && RDATA->fadeAlpha * RDATA->alpha == 255.f) {
@@ -80,16 +79,22 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID) {
if (!(!PWORKSPACE->m_bHasFullscreenWindow || pWindow->m_bIsFullscreen || (pWindow->m_bIsFloating && pWindow->m_bCreatedOverFullscreen)))
return false;
if (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()) {
return true;
} else {
if (!(!PWORKSPACE->m_bHasFullscreenWindow || pWindow->m_bIsFullscreen || (pWindow->m_bIsFloating && pWindow->m_bCreatedOverFullscreen)))
return false;
}
}
if (pWindow->m_iWorkspaceID == pMonitor->activeWorkspace)
return true;
// if not, check if it maybe is active on a different monitor. vvv might be animation in progress
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && PWORKSPACE->m_bForceRendering) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
return true;
// if not, check if it maybe is active on a different monitor.
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) ||
(PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && PWORKSPACE->m_bForceRendering) || // vvvv might be in animation progress vvvvv
(PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
return !pWindow->m_bIsFullscreen; // Do not draw fullscreen windows on other monitors
if (pMonitor->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
return true;
@@ -127,6 +132,9 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen){
if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
continue;
if (w->m_iMonitorID != pMonitor->ID)
continue;
}
if (w->m_iWorkspaceID == pMonitor->activeWorkspace && !w->m_bIsFullscreen)
@@ -256,10 +264,11 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
if (renderdata.decorate) {
if (renderdata.decorate && pWindow->m_sSpecialRenderData.border) {
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding;
rounding *= pMonitor->scale;
auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col();
col.a *= renderdata.fadeAlpha * renderdata.alpha / 255.f;
@@ -306,6 +315,18 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times
wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata);
}
void CHyprRenderer::renderIMEPopup(SIMEPopup* pPopup, CMonitor* pMonitor, timespec* time) {
SRenderData renderdata = {pMonitor->output, time, pPopup->realX, pPopup->realY};
renderdata.blur = false;
renderdata.surface = pPopup->pSurface->surface;
renderdata.decorate = false;
renderdata.w = pPopup->pSurface->surface->current.width;
renderdata.h = pPopup->pSurface->surface->current.height;
wlr_surface_for_each_surface(pPopup->pSurface->surface, renderSurface, &renderdata);
}
void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(ID);
@@ -405,6 +426,12 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
renderLayer(ls.get(), PMONITOR, time);
}
// Render IME popups
for (auto& imep : g_pInputManager->m_sIMERelay.m_lIMEPopups) {
renderIMEPopup(&imep, PMONITOR, time);
}
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
renderLayer(ls.get(), PMONITOR, time);
}
@@ -654,6 +681,9 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
if (!pSurface)
return; // wut?
if (g_pCompositor->m_bUnsafeState)
return;
pixman_region32_t damageBox;
pixman_region32_init(&damageBox);
wlr_surface_get_effective_damage(pSurface, &damageBox);
@@ -694,6 +724,9 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
}
void CHyprRenderer::damageWindow(CWindow* pWindow) {
if (g_pCompositor->m_bUnsafeState)
return;
wlr_box damageBox = pWindow->getFullWindowBoundingBox();
for (auto& m : g_pCompositor->m_vMonitors) {
wlr_box fixedDamageBox = {damageBox.x - m->vecPosition.x, damageBox.y - m->vecPosition.y, damageBox.width, damageBox.height};
@@ -708,6 +741,9 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) {
}
void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
if (g_pCompositor->m_bUnsafeState)
return;
wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
wlr_output_damage_add_box(pMonitor->damage, &damageBox);
@@ -718,6 +754,9 @@ void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
}
void CHyprRenderer::damageBox(wlr_box* pBox) {
if (g_pCompositor->m_bUnsafeState)
return;
for (auto& m : g_pCompositor->m_vMonitors) {
wlr_box damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height};
scaleBox(&damageBox, m->scale);
@@ -778,7 +817,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
if (pMonitor->m_bEnabled)
pMonitor->onDisconnect();
return false;
return true;
}
if (!pMonitor->m_bEnabled) {
@@ -787,7 +826,14 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
// Check if the rule isn't already applied
if (!force && DELTALESSTHAN(pMonitor->vecPixelSize.x, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(pMonitor->vecPixelSize.y, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1) && pMonitor->scale == pMonitorRule->scale && DELTALESSTHAN(pMonitor->vecPosition.x, pMonitorRule->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, pMonitorRule->offset.y, 1) && pMonitor->transform == pMonitorRule->transform) {
if (!force
&& DELTALESSTHAN(pMonitor->vecPixelSize.x, pMonitorRule->resolution.x, 1)
&& DELTALESSTHAN(pMonitor->vecPixelSize.y, pMonitorRule->resolution.y, 1)
&& DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1)
&& pMonitor->scale == pMonitorRule->scale
&& ((DELTALESSTHAN(pMonitor->vecPosition.x, pMonitorRule->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, pMonitorRule->offset.y, 1)) || pMonitorRule->offset == Vector2D(-1, -1))
&& pMonitor->transform == pMonitorRule->transform) {
Debug::log(LOG, "Not applying a new rule to %s because it's already applied!", pMonitor->szName.c_str());
return true;
}
@@ -859,6 +905,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} else {
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
pMonitor->vecSize = pMonitorRule->resolution;
Debug::log(LOG, "Setting custom mode for %s", pMonitor->output->name);
}
} else {
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
@@ -896,6 +944,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
Debug::log(LOG, "Setting preferred mode for %s", pMonitor->output->name);
}
}
@@ -918,9 +968,23 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor();
pMonitor->vecTransformedSize = Vector2D(x,y);
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitorRule->offset.x, (int)pMonitorRule->offset.y);
if (pMonitorRule->offset == Vector2D(-1, -1)) {
// let's find manually a sensible position for it, to the right.
Vector2D finalPos;
//wlr_output_damage_add_whole(pMonitor->damage);
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->ID == pMonitor->ID)
continue;
if (m->vecPosition.x + std::ceil(m->vecSize.x) > finalPos.x) {
finalPos.x = m->vecPosition.x + std::ceil(m->vecSize.x);
}
}
pMonitor->vecPosition = finalPos;
}
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y);
wlr_output_enable(pMonitor->output, true);

View File

@@ -51,6 +51,7 @@ private:
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode);
void renderLayer(SLayerSurface*, CMonitor*, timespec*);
void renderDragIcon(CMonitor*, timespec*);
void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*);
bool m_bHasARenderedCursor = true;

View File

@@ -10,4 +10,11 @@ GLint CShader::getUniformLocation(const std::string& unif) {
}
return itpos->second;
}
CShader::~CShader() {
// destroy shader
if (program != 0) {
glDeleteProgram(program);
}
}

View File

@@ -5,7 +5,9 @@
class CShader {
public:
GLuint program;
~CShader();
GLuint program = 0;
GLint proj;
GLint color;
GLint tex;

View File

@@ -80,6 +80,8 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) {
return; // cannot parse
}
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ? 0 : (m_pWindow->m_sAdditionalConfigData.rounding == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding);
// update the extents
m_seExtents = {{*PSHADOWSIZE + 2 - offset.x, *PSHADOWSIZE + 2 - offset.y}, {*PSHADOWSIZE + 2 + offset.x, *PSHADOWSIZE + 2 + offset.y}};
@@ -92,12 +94,14 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) {
if (fullBox.width < 1 || fullBox.height < 1)
return; // don't draw invisible shadows
g_pHyprOpenGL->scissor((wlr_box *)nullptr);
if (*PSHADOWIGNOREWINDOW) {
glEnable(GL_STENCIL_TEST);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
@@ -106,18 +110,20 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) {
scaleBox(&windowBox, pMonitor->scale);
if (windowBox.width < 1 || windowBox.height < 1) {
glDisable(GL_STENCIL_TEST);
return; // prevent assert failed
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glDisable(GL_STENCIL_TEST);
return; // prevent assert failed
}
g_pHyprOpenGL->renderRect(&windowBox, CColor(0,0,0,0), *PROUNDING);
g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 0), ROUNDING * pMonitor->scale);
glStencilFunc(GL_NOTEQUAL, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
}
scaleBox(&fullBox, pMonitor->scale);
g_pHyprOpenGL->renderRoundedShadow(&fullBox, *PROUNDING, *PSHADOWSIZE, a);
g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, a);
if (*PSHADOWIGNOREWINDOW) {
// cleanup

View File

@@ -112,7 +112,7 @@ static void workspace_handle_remove(struct wl_client *client,
return;
}
wlr_signal_emit_safe(&workspace->events.remove_request, NULL);
wl_signal_emit_mutable(&workspace->events.remove_request, NULL);
}
static void workspace_handle_deactivate(struct wl_client *client,
@@ -312,7 +312,7 @@ void wlr_ext_workspace_handle_v1_destroy(
return;
}
wlr_signal_emit_safe(&workspace->events.destroy, workspace);
wl_signal_emit_mutable(&workspace->events.destroy, workspace);
workspace_manager_update_idle_source(workspace->group->manager);
@@ -338,7 +338,7 @@ static void workspace_group_handle_handle_create_workspace(struct wl_client *cli
struct wlr_ext_workspace_group_handle_v1_create_workspace_event event;
event.workspace_group = group;
event.name = arg;
wlr_signal_emit_safe(&group->events.create_workspace_request, &event);
wl_signal_emit_mutable(&group->events.create_workspace_request, &event);
}
static void workspace_group_handle_handle_destroy(struct wl_client *client,
@@ -513,7 +513,7 @@ void wlr_ext_workspace_group_handle_v1_destroy(
wlr_ext_workspace_handle_v1_destroy(workspace);
}
wlr_signal_emit_safe(&group->events.destroy, group);
wl_signal_emit_mutable(&group->events.destroy, group);
workspace_manager_update_idle_source(group->manager);
struct wlr_ext_workspace_group_handle_v1_output *output, *tmp2;
@@ -556,7 +556,7 @@ static void workspace_manager_commit(struct wl_client *client,
}
}
wlr_signal_emit_safe(&manager->events.commit, manager);
wl_signal_emit_mutable(&manager->events.commit, manager);
}
static void workspace_manager_stop(struct wl_client *client,
@@ -602,7 +602,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
struct wlr_ext_workspace_manager_v1 *manager =
wl_container_of(listener, manager, display_destroy);
wlr_signal_emit_safe(&manager->events.destroy, manager);
wl_signal_emit_mutable(&manager->events.destroy, manager);
wl_list_remove(&manager->display_destroy.link);
wl_global_destroy(manager->global);