Compare commits

..

241 Commits

Author SHA1 Message Date
vaxerski
fba7ed97fb don't refocus if candidate is last window 2022-08-23 23:15:04 +02:00
vaxerski
fd70a9184b fix logic in fullscreen close candidates 2022-08-23 23:09:28 +02:00
vaxerski
0a9ac47030 remove unintuitive candidate behavior 2022-08-23 18:25:33 +02:00
vaxerski
e2450247c0 minor fixes to candidate finding 2022-08-23 18:18:18 +02:00
vaxerski
973540bbc5 minor fix on unfocus on fullscreen workspace 2022-08-23 18:01:22 +02:00
vaxerski
f9b2aa5468 don't round popups 2022-08-23 16:54:32 +02:00
vaxerski
451659ec34 fix oversized popup misalignment 2022-08-23 16:52:36 +02:00
vaxerski
a9e34cba93 move monitor damage to separate funcs 2022-08-23 16:07:47 +02:00
vaxerski
48c9e9d83d damage on force warp resize 2022-08-23 15:08:15 +02:00
vaxerski
23c5760538 IME Popup damage fixes 2022-08-23 11:16:35 +02:00
vaxerski
9bfa3ebc50 fix up keyword to accept spaced args 2022-08-22 23:25:11 +02:00
Mihai Fufezan
8feb6f7da1 Nix: add shortRev to version 2022-08-23 00:17:00 +03:00
vaxerski
fb0e81c18e fix up hyprctl dispatch 2022-08-22 19:16:35 +02:00
vaxerski
359df96d53 fix wlr logging 2022-08-22 18:58:29 +02:00
vaxerski
63493b5736 use a custom logging func for wlr 2022-08-22 18:50:38 +02:00
vaxerski
6565c31dbf fix IME grab on multiple open native inputs 2022-08-22 18:40:38 +02:00
vaxerski
575bfa40e5 added misc:float_switch_override_focus 2022-08-22 18:22:26 +02:00
vaxerski
429b2bffed fix minor refocus issue 2022-08-22 18:16:32 +02:00
vaxerski
c83948ea9a added HYPRLAND_LOG_WLR envvar 2022-08-22 15:50:08 +02:00
vaxerski
8a6e29974b [gha] build man pages 2022-08-22 13:16:57 +00:00
Vaxry
4c6d9b7d5a Merge pull request #555 from viperML/update-man
docs: build man pages to repo
2022-08-22 15:16:32 +02:00
Vaxry
9f5e099cd1 Merge pull request #562 from sp1ritCS/s/ospatches
openSUSE patches
2022-08-22 14:47:17 +02:00
vaxerski
8b39a1cf9b always use /usr/share/ for wayland-sessions 2022-08-22 14:46:53 +02:00
Florian sp1rit​
e9551731f0 improve compatability with older meson versions
- changed <compiler>.get_version() to <compiler>.version()

Signed-off-by: Florian "sp1rit"​ <sp1ritCS@protonmail.com>
2022-08-22 14:35:49 +02:00
Florian sp1rit​
39a9980fb1 dropped deprecated gethostbyname check
Done to avoid the rpmlint warning:
hyprland.x86_64: W: binary-or-shlib-calls-gethostbyname /usr/bin/hyprctl
The binary calls gethostbyname. Please port the code to use getaddrinfo.

Signed-off-by: Florian "sp1rit"​ <sp1ritCS@protonmail.com>
2022-08-22 14:35:41 +02:00
vaxerski
d0ec2b72ae report sizes to all windows on fullscreen 2022-08-22 14:22:21 +02:00
vaxerski
e97fa4e26b destroy monitor resources on exit 2022-08-22 14:17:25 +02:00
vaxerski
52318692f0 clean up temp logic in snapshots 2022-08-22 13:38:40 +02:00
vaxerski
86be6c3884 fix LS snapshot rendering logic 2022-08-22 13:36:00 +02:00
vaxerski
21bea0fcb4 typo 2022-08-22 11:37:00 +02:00
vaxerski
83f7fee3f5 fullscreen request only when mapped 2022-08-22 11:35:46 +02:00
vaxerski
f273ebed9c fix another edge case for fullscreen default windows 2022-08-21 23:24:57 +02:00
vaxerski
3cb30e7fb0 fix crash 2022-08-21 23:16:54 +02:00
vaxerski
3e9a8a7bc8 set new optimizations for blur in example configs 2022-08-21 22:59:19 +02:00
vaxerski
7ca50d7566 handle fullscreen pre-map
stupid-ass qt
2022-08-21 22:30:48 +02:00
vaxerski
ebe07c6656 fix incorrect popup handling on oversized 2022-08-21 21:23:05 +02:00
vaxerski
ce62a98470 fix warn 2022-08-21 18:35:45 +02:00
vaxerski
8faac0c9ac minor activewindow and focus fixes 2022-08-21 18:34:38 +02:00
Fernando Ayats
fea6d7deb0 docs: install manpages with meson 2022-08-21 18:00:04 +02:00
Fernando Ayats
463bc7ab13 doc: install mapages 2022-08-21 17:28:56 +02:00
Vaxry
c4ba11729f Merge pull request #557 from xDarksome/main
Add window{open/close/move} IPC events (#549)
2022-08-21 17:10:24 +02:00
vaxerski
5569e1f69c remove unused func 2022-08-21 17:09:35 +02:00
vaxerski
da725d7aa5 warn about outdated keybind cfg 2022-08-21 17:01:32 +02:00
Darksome
f7f3446882 CCompositor::moveWindowToWorkspace -> CWindow::moveToWorkspace 2022-08-21 18:01:26 +03:00
vaxerski
0f63077a07 use a custom translation state in keybinds 2022-08-21 16:43:22 +02:00
xDarksome
0f25f3aee3 Merge branch 'hyprwm:main' into main 2022-08-21 16:03:51 +03:00
Vaxry
5e1f2539cb Merge pull request #352 from CharlesEkkel/previous-workspace
Add switching to previous workspace
2022-08-21 14:16:52 +02:00
Charles Taylor
9dbdd66da4 fix retrieval of monitor 2022-08-21 22:11:40 +10:00
Charles Taylor
6ec932d11f fix bug which allowed a switch to workspace ID -1.
This only happened for the workspace_back_and_forth setting, since it
was missing a check.
2022-08-21 22:05:35 +10:00
Charles Taylor
3c8c605541 fix style conflicts and config + monitor retrieval 2022-08-21 21:58:46 +10:00
Charles Taylor
9ee42836d5 add general:allow_workspace_cycles option 2022-08-21 20:47:56 +10:00
Charles Taylor
d6ff7e40cf add general:workspace_back_and_forth option 2022-08-21 20:40:06 +10:00
Charles Taylor
04f0efadc3 add switching to previous workspace 2022-08-21 20:21:21 +10:00
viperML
12cdca7422 [gha] build man pages 2022-08-21 08:40:27 +00:00
Fernando Ayats
7ce2c91673 doc: build man pages to repo 2022-08-21 10:39:47 +02:00
Fernando Ayats
aaba11b7a2 gha: build man pages 2022-08-21 10:33:45 +02:00
vaxerski
9513031da3 fix a minor border issue 2022-08-20 22:45:30 +02:00
vaxerski
08e874bcf9 fix special workspace windows being xray with new optim 2022-08-20 20:16:04 +02:00
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
Darksome
776750ee34 Merge branch 'main' of github.com:xDarksome/Hyprland 2022-08-20 13:26:31 +03:00
Darksome
37e1450a4d Impl CCompositor::moveWindowToWorkspace 2022-08-20 13:25:56 +03: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
xDarksome
4af95d4253 Merge branch 'hyprwm:main' into main 2022-08-18 22:24:00 +03:00
Darksome
844c33c980 Add mapwindow, unmapwindow and movewindow IPC events 2022-08-18 22:23:28 +03: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
66 changed files with 3061 additions and 830 deletions

26
.github/workflows/man-update.yaml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Build man pages
on:
workflow_dispatch:
push:
paths:
- docs/**
jobs:
main:
name: Build man pages
runs-on: ubuntu-latest
steps:
- name: Install deps
run: sudo apt install pandoc
- name: Clone repository
uses: actions/checkout@v3
# Not needed
# with:
# submodules: recursive
- name: Build man pages
run: make man
- uses: stefanzweifel/git-auto-commit-action@v4
name: Commit
with:
commit_message: "[gha] build man pages"

4
.gitignore vendored
View File

@@ -10,7 +10,7 @@ CTestTestfile.cmake
_deps _deps
build/ build/
result result*
/.vscode/ /.vscode/
.envrc .envrc
.cache .cache
@@ -24,4 +24,4 @@ hyprctl/hyprctl
gmon.out gmon.out
*.out *.out
*.tar.gz *.tar.gz

View File

@@ -126,8 +126,8 @@ install:
make release make release
cd hyprctl && make all && cd .. cd hyprctl && make all && cd ..
mkdir -p ${PREFIX}/share/wayland-sessions mkdir -p /usr/share/wayland-sessions
cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions/ cp ./example/hyprland.desktop /usr/share/wayland-sessions/
mkdir -p ${PREFIX}/bin mkdir -p ${PREFIX}/bin
cp ./build/Hyprland ${PREFIX}/bin cp ./build/Hyprland ${PREFIX}/bin
cp ./hyprctl/hyprctl ${PREFIX}/bin cp ./hyprctl/hyprctl ${PREFIX}/bin
@@ -136,12 +136,16 @@ install:
cp ./assets/wall_4K.png ${PREFIX}/share/hyprland cp ./assets/wall_4K.png ${PREFIX}/share/hyprland
cp ./assets/wall_8K.png ${PREFIX}/share/hyprland cp ./assets/wall_8K.png ${PREFIX}/share/hyprland
install -Dm644 -t ${PREFIX}/share/man/man1 ./docs/*.1
uninstall: uninstall:
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
rm -f ${PREFIX}/bin/Hyprland rm -f ${PREFIX}/bin/Hyprland
rm -f ${PREFIX}/bin/hyprctl rm -f ${PREFIX}/bin/hyprctl
rm -f /usr/lib/libwlroots.so.11032 rm -f /usr/lib/libwlroots.so.11032
rm -rf ${PREFIX}/share/hyprland rm -rf ${PREFIX}/share/hyprland
rm -f ${PREFIX}/share/man/man1/Hyprland.1
rm -f ${PREFIX}/share/man/man1/hyprctl.1
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o
@@ -167,7 +171,7 @@ man:
--variable=date:"${DATE}" \ --variable=date:"${DATE}" \
--variable=section:1 \ --variable=section:1 \
--from rst \ --from rst \
--to man | gzip -c > /usr/share/man/man1/Hyprland.1.gz --to man > ./docs/Hyprland.1
pandoc ./docs/hyprctl.1.rst \ pandoc ./docs/hyprctl.1.rst \
--standalone \ --standalone \
@@ -175,4 +179,4 @@ man:
--variable=date:"${DATE}" \ --variable=date:"${DATE}" \
--variable=section:1 \ --variable=section:1 \
--from rst \ --from rst \
--to man | gzip -c > /usr/share/man/man1/hyprctl.1.gz --to man > ./docs/hyprctl.1

View File

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

46
docs/Hyprland.1 Normal file
View File

@@ -0,0 +1,46 @@
.\" Automatically generated by Pandoc 2.5
.\"
.TH "Hyprland" "1" "22 Aug 2022" "" "Hyprland User Manual"
.hy
.SH NAME
.PP
Hyprland \- Dynamic tiling Wayland compositor
.SH SYNOPSIS
.PP
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
.SH DESCRIPTION
.PP
\f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on
wlroots that doesn\[aq]t sacrifice on its looks.
.PP
You can launch Hyprland by either going into a TTY and executing
\f[B]Hyprland\f[R], or with a login manager.
.SH NOTICE
.PP
Hyprland is still in pretty early development compared to some other
Wayland compositors.
.PP
Although Hyprland is pretty stable, it may have some bugs.
.SH CONFIGURATION
.PP
For configuration information please see
<\f[I]https://github.com/hyprwm/Hyprland/wiki\f[R]>.
.SH OPTIONS
.TP
.B \f[B]\-h\f[R], \f[B]\-\-help\f[R]
Show command usage.
.TP
.B \f[B]\-c\f[R], \f[B]\-\-config\f[R]
Specify config file to use.
.SH BUGS
.TP
.B Submit bug reports and request features online at:
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
.SH SEE ALSO
.PP
Sources at: <\f[I]https://github.com/hyprwm/Hyprland\f[R]>
.SH COPYRIGHT
.PP
Copyright (c) 2022, vaxerski
.SH AUTHORS
Vaxerski <\f[I]https://github.com/vaxerski\f[R]>.

145
docs/hyprctl.1 Normal file
View File

@@ -0,0 +1,145 @@
.\" Automatically generated by Pandoc 2.5
.\"
.TH "hyprctl" "1" "22 Aug 2022" "" "hyprctl User Manual"
.hy
.SH NAME
.PP
hyprctl \- Utility for controlling parts of Hyprland from a CLI or a
script
.SH SYNOPSIS
.PP
\f[B]hyprctl\f[R] [\f[I](opt)flags\f[R]] [\f[B]command\f[R]]
[\f[I](opt)args\f[R]]
.SH DESCRIPTION
.PP
\f[B]hyprctl\f[R] is a utility for controlling some parts of the
compositor from a CLI or a script.
.SH CONTROL COMMANDS
.PP
\f[B]dispatch\f[R]
.RS
.PP
Call a dispatcher with an argument.
.PP
An argument must be present.
For dispatchers without parameters it can be anything.
.PP
Returns: \f[I]ok\f[R] on success, and an error message on failure.
.TP
.B Examples:
\f[B]hyprctl\f[R] \f[I]dispatch exec kitty\f[R]
.RS
.PP
\f[B]hyprctl\f[R] \f[I]dispatch pseudo x\f[R]
.RE
.RE
.PP
\f[B]keyword\f[R]
.RS
.PP
Set a config keyword dynamically.
.PP
Returns: \f[I]ok\f[R] on success, and an error message on failure.
.TP
.B Examples:
\f[B]hyprctl\f[R] \f[I]keyword bind SUPER,0,pseudo\f[R]
.RS
.PP
\f[B]hyprctl\f[R] \f[I]keyword general:border_size 10\f[R]
.RE
.RE
.PP
\f[B]reload\f[R]
.RS
.PP
Force a reload of the config file.
.RE
.PP
\f[B]kill\f[R]
.RS
.PP
Enter kill mode, where you can kill an app by clicking on it.
You can exit by pressing ESCAPE.
.RE
.SH INFO COMMANDS
.PP
\f[B]version\f[R]
.RS
.PP
Prints the Hyprland version, flags, commit and branch of build.
.RE
.PP
\f[B]monitors\f[R]
.RS
.PP
Lists all the outputs with their properties.
.RE
.PP
\f[B]workspaces\f[R]
.RS
.PP
Lists all workspaces with their properties.
.RE
.PP
\f[B]clients\f[R]
.RS
.PP
Lists all windows with their properties.
.RE
.PP
\f[B]devices\f[R]
.RS
.PP
Lists all connected input devices.
.RE
.PP
\f[B]activewindow\f[R]
.RS
.PP
Returns the active window name.
.RE
.PP
\f[B]layers\f[R]
.RS
.PP
Lists all the layers.
.RE
.PP
\f[B]splash\f[R]
.RS
.PP
Returns the current random splash.
.RE
.SH OPTIONS
.PP
\f[B]\-\-batch\f[R]
.RS
.PP
Specify a batch of commands to execute.
.TP
.B Example:
\f[B]hyprctl\f[R] \f[I]\-\-batch \[dq]keyword general:border_size 2 ;
keyword general:gaps_out 20\[dq]\f[R]
.RS
.PP
\f[I];\f[R] separates the commands.
.RE
.RE
.PP
\f[B]\-j\f[R]
.RS
.PP
Outputs information in JSON.
.RE
.SH BUGS
.TP
.B Submit bug reports and request features online at:
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
.SH SEE ALSO
.PP
Sources at: <\f[I]https://github.com/hyprwm/Hyprland\f[R]>
.SH COPYRIGHT
.PP
Copyright (c) 2022, vaxerski
.SH AUTHORS
Vaxerski <\f[I]https://github.com/vaxerski\f[R]>.

2
docs/meson.build Normal file
View File

@@ -0,0 +1,2 @@
install_man ('Hyprland.1')
install_man ('hyprctl.1')

View File

@@ -8,10 +8,11 @@
# For a full list, see the wiki (basic and advanced configuring) # For a full list, see the wiki (basic and advanced configuring)
# #
monitor=,preferred,0x0,1 monitor=,preferred,auto,1
workspace=DP-1,1 workspace=DP-1,1
input { input {
kb_file=
kb_layout= kb_layout=
kb_variant= kb_variant=
kb_model= kb_model=
@@ -44,10 +45,8 @@ decoration {
rounding=10 rounding=10
blur=1 blur=1
blur_size=3 # minimum 1 blur_size=3 # minimum 1
blur_passes=1 # minimum 1, more passes = more resource intensive. blur_passes=1 # minimum 1
# Your blur "amount" is blur_size * blur_passes, but high blur_size (over around 5-ish) will produce artifacts. blur_new_optimizations=1
# if you want heavy blur, you need to up the blur_passes.
# the more passes, the more you can up the blur_size without noticing artifacts.
} }
animations { animations {
@@ -112,4 +111,4 @@ bind=ALT,9,movetoworkspace,9
bind=ALT,0,movetoworkspace,10 bind=ALT,0,movetoworkspace,10
bind=SUPER,mouse_down,workspace,e+1 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": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1659219666, "lastModified": 1660908602,
"narHash": "sha256-pzYr5fokQPHv7CmUXioOhhzDy/XyWOIXP4LZvv/T7Mk=", "narHash": "sha256-SwZ85IPWvC4NxxFhWhRMTJpApSHbY1u4YK2UFWEBWvY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "7b9be38c7250b22d829ab6effdee90d5e40c6e5c", "rev": "495b19d5b3e62b4ec7e846bdfb6ef3d9c3b83492",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -26,11 +26,11 @@
"flake": false, "flake": false,
"locked": { "locked": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"lastModified": 1658770113, "lastModified": 1660930713,
"narHash": "sha256-VBq9vw0hvQPKGKLNKLJS8xsUHvrX0o2LUDBVolixenE=", "narHash": "sha256-bY7q1NqG/sjCUAWPn/Ne9NCigLlPlH5Lk1WCMqv3rTU=",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "7b5e890e61a27375725068a7d1884b26851b3102", "rev": "7c575922c05e4d5fd9a403c2aa631a54c7531d44",
"type": "gitlab" "type": "gitlab"
}, },
"original": { "original": {

View File

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

View File

@@ -34,6 +34,8 @@ commands:
splash splash
hyprpaper hyprpaper
reload reload
setcursor
getoption
flags: flags:
-j -> output in JSON -j -> output in JSON
@@ -48,12 +50,6 @@ void request(std::string arg) {
return; return;
} }
const auto SERVER = gethostbyname("localhost");
if (!SERVER) {
std::cout << "Couldn't get host (2)";
return;
}
// get the instance signature // get the instance signature
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE"); auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
@@ -156,7 +152,10 @@ void dispatchRequest(int argc, char** argv) {
return; return;
} }
std::string rq = "/dispatch " + std::string(argv[2]) + " " + std::string(argv[3]); std::string rq = "/dispatch";
for(int i = 2; i < argc; i++)
rq += " " + std::string(argv[i]);
request(rq); request(rq);
} }
@@ -167,7 +166,10 @@ void keywordRequest(int argc, char** argv) {
return; return;
} }
std::string rq = "keyword " + std::string(argv[2]) + " " + std::string(argv[3]); std::string rq = "/keyword";
for(int i = 2; i < argc; i++)
rq += " " + std::string(argv[i]);
request(rq); request(rq);
} }
@@ -183,6 +185,17 @@ void hyprpaperRequest(int argc, char** argv) {
requestHyprpaper(rq); 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) { void batchRequest(std::string arg) {
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1); 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("/splash")) request(fullRequest);
else if (fullRequest.contains("/devices")) request(fullRequest); else if (fullRequest.contains("/devices")) request(fullRequest);
else if (fullRequest.contains("/reload")) 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("/dispatch")) dispatchRequest(argc, argv);
else if (fullRequest.contains("/keyword")) keywordRequest(argc, argv); else if (fullRequest.contains("/keyword")) keywordRequest(argc, argv);
else if (fullRequest.contains("/hyprpaper")) hyprpaperRequest(argc, argv); else if (fullRequest.contains("/hyprpaper")) hyprpaperRequest(argc, argv);

View File

@@ -1,8 +1,22 @@
project('Hyprland', 'cpp', 'c', project('Hyprland', 'cpp', 'c',
version : '0.8.1beta', version : '0.10.0beta',
default_options : ['warning_level=2', 'default_library=static', 'optimization=3']) 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.version() + ') with required C++ standard (C++23)')
endif
GIT_BRANCH = run_command('git', 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip() 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() GIT_COMMIT_HASH = run_command('git', 'rev-parse', 'HEAD', check: false).stdout().strip()
@@ -45,3 +59,4 @@ subdir('src')
subdir('hyprctl') subdir('hyprctl')
subdir('assets') subdir('assets')
subdir('example') subdir('example')
subdir('docs')

View File

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

View File

@@ -65,9 +65,11 @@ in {
xdg.configFile."hypr/hyprland.conf" = { xdg.configFile."hypr/hyprland.conf" = {
text = text =
(lib.optionalString cfg.systemdIntegration " (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 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; + cfg.extraConfig;
onChange = let onChange = let
@@ -75,7 +77,7 @@ in {
if cfg.package == null if cfg.package == null
then defaultHyprlandPackage then defaultHyprlandPackage
else cfg.package; 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 { 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_sWLRPointerGestures = wlr_pointer_gestures_v1_create(m_sWLDisplay);
m_sWLRSession = wlr_backend_get_session(m_sWLRBackend); 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() { 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_begin, &Events::listen_pinchBegin, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.pinch_update, &Events::listen_pinchUpdate, 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.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_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_cursor, &Events::listen_requestMouse, &m_sSeat, "Seat");
addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &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_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_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_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_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer");
addWLSignal(&m_sWLRIdleInhibitMgr->events.new_inhibitor, &Events::listen_newIdleInhibitor, m_sWLRIdleInhibitMgr, "WLRIdleInhibitMgr"); 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_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) if (m_sWLRSession)
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session"); addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
} }
@@ -214,6 +225,9 @@ void CCompositor::cleanup() {
m_vWorkspaces.clear(); m_vWorkspaces.clear();
m_vWindows.clear(); m_vWindows.clear();
for (auto& m : m_vMonitors)
g_pHyprOpenGL->destroyMonitorResources(m.get());
if (g_pXWaylandManager->m_sWLRXWayland) { if (g_pXWaylandManager->m_sWLRXWayland) {
wlr_xwayland_destroy(g_pXWaylandManager->m_sWLRXWayland); wlr_xwayland_destroy(g_pXWaylandManager->m_sWLRXWayland);
g_pXWaylandManager->m_sWLRXWayland = nullptr; g_pXWaylandManager->m_sWLRXWayland = nullptr;
@@ -222,6 +236,14 @@ void CCompositor::cleanup() {
wl_display_terminate(m_sWLDisplay); wl_display_terminate(m_sWLDisplay);
m_sWLDisplay = nullptr; 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() { void CCompositor::startCompositor() {
@@ -460,13 +482,13 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceOpen) { if (PMONITOR->specialWorkspaceOpen) {
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { 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}; 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(); return (*w).get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; 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(); return w.get();
} }
} }
@@ -474,7 +496,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. // 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++) { 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}; 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)) if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y))
return w->get(); return w->get();
@@ -492,7 +514,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// for windows, we need to check their extensions too, first. // for windows, we need to check their extensions too, first.
for (auto& w : m_vWindows) { 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; wlr_surface* resultSurf = nullptr;
Vector2D origin = w->m_vRealPosition.vec(); Vector2D origin = w->m_vRealPosition.vec();
SExtensionFindingData data = {origin, pos, &resultSurf}; SExtensionFindingData data = {origin, pos, &resultSurf};
@@ -504,7 +526,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; 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(); return w.get();
} }
@@ -604,7 +626,21 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
} }
if (!pWindow || !windowValidMapped(pWindow)) { 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); wlr_seat_keyboard_notify_clear_focus(m_sSeat.seat);
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
m_pLastFocus = nullptr;
return; return;
} }
@@ -616,6 +652,9 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
if (m_pLastWindow == pWindow && m_sSeat.seat->keyboard_state.focused_surface == pSurface) if (m_pLastWindow == pWindow && m_sSeat.seat->keyboard_state.focused_surface == pSurface)
return; return;
if (!isWorkspaceVisible(pWindow->m_iWorkspaceID))
g_pKeybindManager->changeworkspace("[internal]" + std::to_string(pWindow->m_iWorkspaceID));
const auto PLASTWINDOW = m_pLastWindow; const auto PLASTWINDOW = m_pLastWindow;
m_pLastWindow = pWindow; m_pLastWindow = pWindow;
@@ -665,6 +704,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
if (!pSurface) { if (!pSurface) {
wlr_seat_keyboard_clear_focus(m_sSeat.seat); wlr_seat_keyboard_clear_focus(m_sSeat.seat);
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused
g_pInputManager->m_sIMERelay.onKeyboardFocus(nullptr);
return; return;
} }
@@ -676,12 +716,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); 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 = { wlr_seat_keyboard_focus_change_event event = {
.seat = m_sSeat.seat, .seat = m_sSeat.seat,
.old_surface = m_pLastFocus, .old_surface = m_pLastFocus,
.new_surface = pSurface, .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) if (pWindowOwner)
Debug::log(LOG, "Set keyboard focus to surface %x, with window name: %s", pSurface, pWindowOwner->m_szTitle.c_str()); Debug::log(LOG, "Set keyboard focus to surface %x, with window name: %s", pSurface, pWindowOwner->m_szTitle.c_str());
@@ -819,31 +861,6 @@ CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) {
return nullptr; 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) { bool CCompositor::doesSeatAcceptInput(wlr_surface* surface) {
return !m_sSeat.exclusiveClient || (surface && m_sSeat.exclusiveClient == wl_resource_get_client(surface->resource)); return !m_sSeat.exclusiveClient || (surface && m_sSeat.exclusiveClient == wl_resource_get_client(surface->resource));
} }
@@ -1272,16 +1289,9 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
} }
} }
void CCompositor::moveWindowToWorkspace(CWindow* pWindow, const std::string& work) {
m_pLastWindow = pWindow;
g_pKeybindManager->moveActiveToWorkspace(work);
g_pInputManager->refocus();
}
int CCompositor::getNextAvailableMonitorID() { int CCompositor::getNextAvailableMonitorID() {
int64_t topID = -1; int64_t topID = -1;
for (auto& m : m_vMonitors) { for (auto& m : m_vRealMonitors) {
if ((int64_t)m->ID > topID) if ((int64_t)m->ID > topID)
topID = m->ID; topID = m->ID;
} }
@@ -1338,6 +1348,8 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
if (w->m_bIsFloating && w->m_bIsMapped && !w->m_bHidden) { if (w->m_bIsFloating && w->m_bIsMapped && !w->m_bHidden) {
w->m_vRealPosition = w->m_vRealPosition.vec() - POLDMON->vecPosition + pMonitor->vecPosition; w->m_vRealPosition = w->m_vRealPosition.vec() - POLDMON->vecPosition + pMonitor->vecPosition;
} }
w->updateToplevel();
} }
} }
@@ -1380,14 +1392,21 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
if (!windowValidMapped(pWindow)) if (!windowValidMapped(pWindow))
return; return;
focusWindow(pWindow);
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, mode, on); g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, mode, on);
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL); g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL);
// make all windows on the same workspace under the fullscreen window // make all windows on the same workspace under the fullscreen window
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID) if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID)
w->m_bCreatedOverFullscreen = false; w->m_bCreatedOverFullscreen = false;
} }
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv(), true);
forceReportSizesToWindowsOnWorkspace(pWindow->m_iWorkspaceID);
} }
void CCompositor::moveUnmanagedX11ToWindows(CWindow* pWindow) { void CCompositor::moveUnmanagedX11ToWindows(CWindow* pWindow) {
@@ -1518,3 +1537,81 @@ void CCompositor::warpCursorTo(const Vector2D& pos) {
wlr_cursor_warp(m_sWLRCursor, m_sSeat.mouse->mouse, pos.x, pos.y); 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);
}
}
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);
}
void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == wid && w->m_bIsMapped && !w->m_bHidden) {
g_pXWaylandManager->setWindowSize(w.get(), w->m_vRealSize.vec(), true);
}
}
}

View File

@@ -66,6 +66,8 @@ public:
wlr_idle_inhibit_manager_v1* m_sWLRIdleInhibitMgr; wlr_idle_inhibit_manager_v1* m_sWLRIdleInhibitMgr;
wlr_pointer_gestures_v1* m_sWLRPointerGestures; wlr_pointer_gestures_v1* m_sWLRPointerGestures;
wlr_output_power_manager_v1* m_sWLROutputPowerMgr; 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_bReadyToProcess = false;
bool m_bSessionActive = true; bool m_bSessionActive = true;
bool m_bDPMSStateON = 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&); void updateWorkspaceWindowDecos(const int&);
int getWindowsOnWorkspace(const int&); int getWindowsOnWorkspace(const int&);
CWindow* getFirstWindowOnWorkspace(const int&); CWindow* getFirstWindowOnWorkspace(const int&);
void fixXWaylandWindowsOnWorkspace(const int&);
CWindow* getFullscreenWindowOnWorkspace(const int&); CWindow* getFullscreenWindowOnWorkspace(const int&);
bool doesSeatAcceptInput(wlr_surface*); bool doesSeatAcceptInput(wlr_surface*);
bool isWindowActive(CWindow*); bool isWindowActive(CWindow*);
@@ -141,7 +143,6 @@ public:
CMonitor* getMonitorInDirection(const char&); CMonitor* getMonitorInDirection(const char&);
void updateAllWindowsAnimatedDecorationValues(); void updateAllWindowsAnimatedDecorationValues();
void updateWindowAnimatedDecorationValues(CWindow*); void updateWindowAnimatedDecorationValues(CWindow*);
void moveWindowToWorkspace(CWindow*, const std::string&);
int getNextAvailableMonitorID(); int getNextAvailableMonitorID();
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*); void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
bool workspaceIDOutOfBounds(const int&); bool workspaceIDOutOfBounds(const int&);
@@ -153,6 +154,12 @@ public:
void addToFadingOutSafe(CWindow*); void addToFadingOutSafe(CWindow*);
CWindow* getWindowByRegex(const std::string&); CWindow* getWindowByRegex(const std::string&);
void warpCursorTo(const Vector2D&); void warpCursorTo(const Vector2D&);
SLayerSurface* getLayerSurfaceFromWlr(wlr_layer_surface_v1*);
SLayerSurface* getLayerSurfaceFromSurface(wlr_surface*);
void closeWindow(CWindow*);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const int&);
std::string explicitConfigPath; std::string explicitConfigPath;

View File

@@ -112,4 +112,108 @@ IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) {
} }
return nullptr; 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);
}
void CWindow::moveToWorkspace(int workspaceID) {
if (m_iWorkspaceID != workspaceID) {
m_iWorkspaceID = workspaceID;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
if (PWORKSPACE) {
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%x,%s", this, PWORKSPACE->m_szName.c_str())});
}
}
} }

View File

@@ -13,6 +13,7 @@ struct SWindowSpecialRenderData {
// set by the layout // set by the layout
bool rounding = true; bool rounding = true;
bool border = true;
}; };
struct SWindowAdditionalConfigData { struct SWindowAdditionalConfigData {
@@ -39,6 +40,11 @@ public:
DYNLISTENER(requestMinimize); DYNLISTENER(requestMinimize);
DYNLISTENER(requestMaximize); DYNLISTENER(requestMaximize);
DYNLISTENER(requestResize); DYNLISTENER(requestResize);
DYNLISTENER(activateX11);
DYNLISTENER(configureX11);
DYNLISTENER(toplevelClose);
DYNLISTENER(toplevelActivate);
DYNLISTENER(toplevelFullscreen);
// DYNLISTENER(newSubsurfaceWindow); // DYNLISTENER(newSubsurfaceWindow);
union { union {
@@ -58,6 +64,9 @@ public:
Vector2D m_vReportedPosition; Vector2D m_vReportedPosition;
Vector2D m_vReportedSize; Vector2D m_vReportedSize;
// for restoring floating statuses
Vector2D m_vLastFloatingSize;
// this is used for pseudotiling // this is used for pseudotiling
bool m_bIsPseudotiled = false; bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(0,0); Vector2D m_vPseudoSize = Vector2D(0,0);
@@ -84,14 +93,16 @@ public:
uint64_t m_iX11Type = 0; uint64_t m_iX11Type = 0;
bool m_bIsModal = false; bool m_bIsModal = false;
bool m_bX11DoesntWantBorders = false; bool m_bX11DoesntWantBorders = false;
DYNLISTENER(activateX11); bool m_bX11ShouldntFocus = false;
DYNLISTENER(configureX11);
// //
// For nofocus // For nofocus
bool m_bNoFocus = false; bool m_bNoFocus = false;
bool m_bNoInitialFocus = false; bool m_bNoInitialFocus = false;
// initial fullscreen
bool m_bWantsInitialFullscreen = false;
SSurfaceTreeNode* m_pSurfaceTree = nullptr; SSurfaceTreeNode* m_pSurfaceTree = nullptr;
// Animated border // Animated border
@@ -124,6 +135,10 @@ public:
// animated shadow color // animated shadow color
CAnimatedVariable m_cRealShadowColor; CAnimatedVariable m_cRealShadowColor;
// for toplevel monitor events
uint64_t m_iLastToplevelMonitorID = -1;
uint64_t m_iLastSurfaceMonitorID = -1;
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) { 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; 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 +150,9 @@ public:
void updateWindowDecos(); void updateWindowDecos();
pid_t getPID(); pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType); IHyprWindowDecoration* getDecorationByType(eDecorationType);
void createToplevelHandle();
void destroyToplevelHandle();
void updateToplevel();
void updateSurfaceOutputs();
void moveToWorkspace(int);
}; };

View File

@@ -54,6 +54,9 @@ void CConfigManager::setDefaultVars() {
configValues["misc:no_vfr"].intValue = 1; configValues["misc:no_vfr"].intValue = 1;
configValues["misc:damage_entire_on_snapshot"].intValue = 0; configValues["misc:damage_entire_on_snapshot"].intValue = 0;
configValues["misc:mouse_move_enables_dpms"].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:int"].intValue = 0;
configValues["debug:log_damage"].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:special_scale_factor"].floatValue = 0.8f;
configValues["dwindle:split_width_multiplier"].floatValue = 1.0f; configValues["dwindle:split_width_multiplier"].floatValue = 1.0f;
configValues["dwindle:no_gaps_when_only"].intValue = 0; 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:special_scale_factor"].floatValue = 0.8f;
configValues["master:new_is_master"].intValue = 1; configValues["master:new_is_master"].intValue = 1;
@@ -116,6 +120,7 @@ void CConfigManager::setDefaultVars() {
configValues["animations:workspaces"].intValue = 1; configValues["animations:workspaces"].intValue = 1;
configValues["input:sensitivity"].floatValue = 0.f; configValues["input:sensitivity"].floatValue = 0.f;
configValues["input:kb_file"].strValue = STRVAL_EMPTY;
configValues["input:kb_layout"].strValue = "us"; configValues["input:kb_layout"].strValue = "us";
configValues["input:kb_variant"].strValue = STRVAL_EMPTY; configValues["input:kb_variant"].strValue = STRVAL_EMPTY;
configValues["input:kb_options"].strValue = STRVAL_EMPTY; configValues["input:kb_options"].strValue = STRVAL_EMPTY;
@@ -126,6 +131,7 @@ void CConfigManager::setDefaultVars() {
configValues["input:natural_scroll"].intValue = 0; configValues["input:natural_scroll"].intValue = 0;
configValues["input:numlock_by_default"].intValue = 0; configValues["input:numlock_by_default"].intValue = 0;
configValues["input:force_no_accel"].intValue = 0; configValues["input:force_no_accel"].intValue = 0;
configValues["input:float_switch_override_focus"].intValue = 1;
configValues["input:touchpad:natural_scroll"].intValue = 0; configValues["input:touchpad:natural_scroll"].intValue = 0;
configValues["input:touchpad:disable_while_typing"].intValue = 1; configValues["input:touchpad:disable_while_typing"].intValue = 1;
configValues["input:touchpad:clickfinger_behavior"].intValue = 0; configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
@@ -135,6 +141,8 @@ void CConfigManager::setDefaultVars() {
configValues["binds:pass_mouse_when_bound"].intValue = 1; configValues["binds:pass_mouse_when_bound"].intValue = 1;
configValues["binds:scroll_event_delay"].intValue = 300; configValues["binds:scroll_event_delay"].intValue = 300;
configValues["binds:workspace_back_and_forth"].intValue = 0;
configValues["binds:allow_workspace_cycles"].intValue = 0;
configValues["gestures:workspace_swipe"].intValue = 0; configValues["gestures:workspace_swipe"].intValue = 0;
configValues["gestures:workspace_swipe_fingers"].intValue = 3; configValues["gestures:workspace_swipe_fingers"].intValue = 3;
@@ -152,6 +160,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
auto& cfgValues = deviceConfigs[dev]; auto& cfgValues = deviceConfigs[dev];
cfgValues["sensitivity"].floatValue = 0.f; cfgValues["sensitivity"].floatValue = 0.f;
cfgValues["kb_file"].strValue = STRVAL_EMPTY;
cfgValues["kb_layout"].strValue = "us"; cfgValues["kb_layout"].strValue = "us";
cfgValues["kb_variant"].strValue = STRVAL_EMPTY; cfgValues["kb_variant"].strValue = STRVAL_EMPTY;
cfgValues["kb_options"].strValue = STRVAL_EMPTY; cfgValues["kb_options"].strValue = STRVAL_EMPTY;
@@ -433,13 +442,8 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
return; return;
} }
// overwrite if exists if (std::find_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }) != m_dMonitorRules.end())
for (auto& r : m_dMonitorRules) { m_dMonitorRules.erase(std::remove_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }));
if (r.name == newrule.name) {
r = newrule;
return;
}
}
m_dMonitorRules.push_back(newrule); m_dMonitorRules.push_back(newrule);
@@ -454,17 +458,31 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
if (curitem.contains("@")) if (curitem.contains("@"))
newrule.refreshRate = stof(curitem.substr(curitem.find_first_of('@') + 1)); newrule.refreshRate = stof(curitem.substr(curitem.find_first_of('@') + 1));
} }
nextItem(); nextItem();
newrule.offset.x = stoi(curitem.substr(0, curitem.find_first_of('x'))); if (curitem.find("auto") == 0) {
newrule.offset.y = stoi(curitem.substr(curitem.find_first_of('x') + 1)); 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(); nextItem();
newrule.scale = stof(curitem); newrule.scale = stof(curitem);
if (newrule.scale < 0.25f) {
parseError = "not a valid scale.";
newrule.scale = 1;
}
nextItem(); nextItem();
if (curitem != "") { if (curitem != "") {
@@ -474,13 +492,8 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
return; return;
} }
// overwrite if exists if (std::find_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }) != m_dMonitorRules.end())
for (auto& r : m_dMonitorRules) { m_dMonitorRules.erase(std::remove_if(m_dMonitorRules.begin(), m_dMonitorRules.end(), [&](const auto& other) { return other.name == newrule.name; }));
if (r.name == newrule.name) {
r = newrule;
return;
}
}
m_dMonitorRules.push_back(newrule); m_dMonitorRules.push_back(newrule);
} }
@@ -507,13 +520,24 @@ void CConfigManager::handleBezier(const std::string& command, const std::string&
std::string bezierName = curitem; std::string bezierName = curitem;
nextItem(); nextItem();
if (curitem == "")
parseError = "too few arguments";
float p1x = std::stof(curitem); float p1x = std::stof(curitem);
nextItem(); nextItem();
if (curitem == "")
parseError = "too few arguments";
float p1y = std::stof(curitem); float p1y = std::stof(curitem);
nextItem(); nextItem();
if (curitem == "")
parseError = "too few arguments";
float p2x = std::stof(curitem); float p2x = std::stof(curitem);
nextItem(); nextItem();
if (curitem == "")
parseError = "too few arguments";
float p2y = std::stof(curitem); float p2y = std::stof(curitem);
nextItem();
if (curitem != "")
parseError = "too many arguments";
g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y)); g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y));
} }
@@ -568,14 +592,23 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
// on/off // on/off
PANIM->second.internalEnabled = curitem == "1"; PANIM->second.internalEnabled = curitem == "1";
if (curitem != "0" && curitem != "1") {
parseError = "invalid animation on/off state";
}
nextItem(); nextItem();
// speed // speed
if (isNumber(curitem, true)) { if (isNumber(curitem, true)) {
PANIM->second.internalSpeed = std::stof(curitem); PANIM->second.internalSpeed = std::stof(curitem);
if (PANIM->second.internalSpeed <= 0) {
parseError = "invalid speed";
PANIM->second.internalSpeed = 1.f;
}
} else { } else {
PANIM->second.internalSpeed = 10.f; PANIM->second.internalSpeed = 10.f;
parseError = "Invalid speed"; parseError = "invalid speed";
} }
nextItem(); nextItem();
@@ -583,11 +616,23 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
// curve // curve
PANIM->second.internalBezier = curitem; PANIM->second.internalBezier = curitem;
if (!g_pAnimationManager->bezierExists(curitem)) {
parseError = "no such bezier";
PANIM->second.internalBezier = "default";
}
nextItem(); nextItem();
// style // style
PANIM->second.internalStyle = curitem; PANIM->second.internalStyle = curitem;
if (curitem != "") {
const auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, curitem);
if (ERR != "")
parseError = ERR;
}
// now, check for children, recursively // now, check for children, recursively
setAnimForChildren(&PANIM->second); setAnimForChildren(&PANIM->second);
} }
@@ -648,6 +693,11 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
return; return;
} }
if (KEY == "exclam" || KEY == "asciicircum" || KEY == "at") { // just some
parseError = "Your config contains (probably) wrong keys. The SHIFT keysym behavior has changed after v0.10.3beta. Please consult the wiki (Advanced configuring -> binds)";
return;
}
if (KEY != "") { if (KEY != "") {
if (isNumber(KEY) && std::stoi(KEY) > 9) if (isNumber(KEY) && std::stoi(KEY) > 9)
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat}); g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat});
@@ -733,30 +783,13 @@ void CConfigManager::handleSubmap(const std::string& command, const std::string&
} }
void CConfigManager::handleSource(const std::string& command, const std::string& rawpath) { void CConfigManager::handleSource(const std::string& command, const std::string& rawpath) {
static const char* const ENVHOME = getenv("HOME"); if (rawpath.length() < 2) {
auto value = rawpath;
if (value.length() < 2) {
Debug::log(ERR, "source= path garbage"); Debug::log(ERR, "source= path garbage");
parseError = "source path " + value + " bogus!"; parseError = "source path " + rawpath + " bogus!";
return; return;
} }
if (value[0] == '.') { auto value = absolutePath(rawpath, configCurrentPath);
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));
}
if (!std::filesystem::exists(value)) { if (!std::filesystem::exists(value)) {
Debug::log(ERR, "source= file doesnt exist"); Debug::log(ERR, "source= file doesnt exist");
@@ -885,6 +918,7 @@ void CConfigManager::parseLine(std::string& line) {
if (line.contains(" {")) { if (line.contains(" {")) {
auto cat = line.substr(0, line.find(" {")); auto cat = line.substr(0, line.find(" {"));
transform(cat.begin(), cat.end(), cat.begin(), ::tolower); transform(cat.begin(), cat.end(), cat.begin(), ::tolower);
std::replace(cat.begin(), cat.end(), ' ', '-');
if (currentCategory.length() != 0) { if (currentCategory.length() != 0) {
currentCategory.push_back(':'); currentCategory.push_back(':');
currentCategory.append(cat); currentCategory.append(cat);
@@ -1034,14 +1068,15 @@ void CConfigManager::loadConfigLoadVars() {
if (parseError != "") if (parseError != "")
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255)); g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255));
else if (configValues["autogenerated"].intValue == 1) 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 else
g_pHyprError->destroy(); g_pHyprError->destroy();
// Set the modes for all monitors as we configured them // Set the modes for all monitors as we configured them
// not on first launch because monitors might not exist yet // not on first launch because monitors might not exist yet
// and they'll be taken care of in the newMonitor event // 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; m_bWantsMonitorReload = true;
// check // check
@@ -1061,6 +1096,9 @@ void CConfigManager::loadConfigLoadVars() {
// Force the compositor to fully re-render all monitors // Force the compositor to fully re-render all monitors
for (auto& m : g_pCompositor->m_vMonitors) for (auto& m : g_pCompositor->m_vMonitors)
m->forceFullFrames = 2; m->forceFullFrames = 2;
// Reset no monitor reload
m_bNoMonitorReload = false;
} }
void CConfigManager::tick() { void CConfigManager::tick() {
@@ -1109,9 +1147,13 @@ SConfigValue CConfigManager::getConfigValueSafe(const std::string& val) {
SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val) { SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val) {
std::lock_guard<std::mutex> lg(configmtx); 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()) { if (it == deviceConfigs.end()) {
Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", devcopy.c_str());
return SConfigValue(); return SConfigValue();
} }
@@ -1124,7 +1166,7 @@ SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, co
if (foundIt == std::string::npos) if (foundIt == std::string::npos)
continue; continue;
if (foundIt == cv.first.length() - val.length()) { if (cv.first == "input:" + val || cv.first == "input:touchpad:" + cv.first) {
copy = cv.second; copy = cv.second;
} }
} }
@@ -1206,7 +1248,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(std::string name) {
Debug::log(WARN, "No rules configured. Using the default hardcoded one."); 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) { std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
@@ -1275,7 +1317,7 @@ void CConfigManager::performMonitorReload() {
bool overAgain = false; bool overAgain = false;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
auto rule = getMonitorRuleFor(m->szName); auto rule = getMonitorRuleFor(m->szName);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
overAgain = true; overAgain = true;
@@ -1293,8 +1335,20 @@ SConfigValue* CConfigManager::getConfigValuePtr(std::string val) {
return &configValues[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) { 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(); return it != deviceConfigs.end();
} }
@@ -1314,7 +1368,7 @@ void CConfigManager::ensureDPMS() {
auto rule = getMonitorRuleFor(rm->szName); auto rule = getMonitorRuleFor(rm->szName);
if (rule.disabled == rm->m_bEnabled) { if (rule.disabled == rm->m_bEnabled) {
rm->m_pThisWrap = &rm; rm->m_pThisWrap = &rm;
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule); g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
} }
} }
@@ -1323,3 +1377,8 @@ void CConfigManager::ensureDPMS() {
SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::string& name) { SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::string& name) {
return &animationConfig[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&); bool shouldBlurLS(const std::string&);
SConfigValue* getConfigValuePtr(std::string); SConfigValue* getConfigValuePtr(std::string);
SConfigValue* getConfigValuePtrSafe(std::string);
SMonitorRule getMonitorRuleFor(std::string); SMonitorRule getMonitorRuleFor(std::string);
@@ -96,11 +97,17 @@ public:
void performMonitorReload(); void performMonitorReload();
bool m_bWantsMonitorReload = false; bool m_bWantsMonitorReload = false;
bool m_bForceReload = false; bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
void ensureDPMS();
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false); std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
void addParseError(const std::string&);
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&); SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
std::string configCurrentPath;
private: private:
std::deque<std::string> configPaths; // stores all the config paths std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times 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::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 currentCategory = ""; // For storing the category of the current item
std::string parseError = ""; // For storing a parse error to display later std::string parseError = ""; // For storing a parse error to display later
@@ -131,7 +136,6 @@ private:
void setDefaultVars(); void setDefaultVars();
void setDefaultAnimationVars(); void setDefaultAnimationVars();
void setDeviceDefaultVars(const std::string&); void setDeviceDefaultVars(const std::string&);
void ensureDPMS();
void setAnimForChildren(SAnimationPropertyConfig *const); void setAnimForChildren(SAnimationPropertyConfig *const);
@@ -155,4 +159,4 @@ private:
void handleBlurLS(const std::string&, const std::string&); 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. autogenerated=1 # remove this line to get rid of the warning on top.
monitor=,preferred,0x0,1 monitor=,preferred,auto,1
input { input {
kb_file=
kb_layout= kb_layout=
kb_variant= kb_variant=
kb_model= kb_model=
@@ -52,10 +53,8 @@ decoration {
rounding=10 rounding=10
blur=1 blur=1
blur_size=3 # minimum 1 blur_size=3 # minimum 1
blur_passes=1 # minimum 1, more passes = more resource intensive. blur_passes=1 # minimum 1
# Your blur "amount" is blur_size * blur_passes, but high blur_size (over around 5-ish) will produce artifacts. blur_new_optimizations=1
# if you want heavy blur, you need to up the blur_passes.
# the more passes, the more you can up the blur_size without noticing artifacts.
} }
animations { animations {
@@ -122,4 +121,4 @@ bind=ALT,0,movetoworkspace,10
bind=SUPER,mouse_down,workspace,e+1 bind=SUPER,mouse_down,workspace,e+1
bind=SUPER,mouse_up,workspace,e-1 bind=SUPER,mouse_up,workspace,e-1
)#"; )#";

View File

@@ -35,7 +35,7 @@ R"#({
"reserved": [%i, %i, %i, %i], "reserved": [%i, %i, %i, %i],
"scale": %.2f, "scale": %.2f,
"transform": %i, "transform": %i,
"active": "%s" "focused": %s
},)#", },)#",
m->ID, m->ID,
escapeJSONStrings(m->szName).c_str(), 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, (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y,
m->scale, m->scale,
(int)m->transform, (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 += "]"; result += "]";
} else { } else {
for (auto& m : g_pCompositor->m_vMonitors) { 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")); 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, "id": %i,
"name": "%s" "name": "%s"
}, },
"floating": %i, "floating": %s,
"monitor": %i, "monitor": %i,
"class": "%s", "class": "%s",
"title": "%s", "title": "%s",
"pid": %i, "pid": %i,
"xwayland": %i "xwayland": %s
},)#", },)#",
w.get(), w.get(),
(int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y, (int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y,
(int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.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(), 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, w->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(), escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(), escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(),
w->getPID(), w->getPID(),
(int)w->m_bIsX11 ((int)w->m_bIsX11 == 1 ? "true" : "false")
); );
} }
} }
// remove trailing comma // remove trailing comma
result.pop_back(); if (result != "[")
result.pop_back();
result += "]"; result += "]";
} else { } else {
@@ -129,13 +130,13 @@ R"#({
"name": "%s", "name": "%s",
"monitor": "%s", "monitor": "%s",
"windows": %i, "windows": %i,
"hasfullscreen": %i "hasfullscreen": %s
},)#", },)#",
w->m_iID, w->m_iID,
escapeJSONStrings(w->m_szName).c_str(), escapeJSONStrings(w->m_szName).c_str(),
escapeJSONStrings(g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName).c_str(), escapeJSONStrings(g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName).c_str(),
g_pCompositor->getWindowsOnWorkspace(w->m_iID), 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; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!g_pCompositor->windowValidMapped(PWINDOW))
return "Invalid"; return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid";
if (format == HyprCtl::FORMAT_JSON) { if (format == HyprCtl::FORMAT_JSON) {
return getFormat( return getFormat(
@@ -168,23 +169,23 @@ R"#({
"id": %i, "id": %i,
"name": "%s" "name": "%s"
}, },
"floating": %i, "floating": %s,
"monitor": %i, "monitor": %i,
"class": "%s", "class": "%s",
"title": "%s", "title": "%s",
"pid": %i, "pid": %i,
"xwayland": %i "xwayland": %s
})#", })#",
PWINDOW, PWINDOW,
(int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y,
(int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.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(), 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, PWINDOW->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(), escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(), escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(),
PWINDOW->getPID(), PWINDOW->getPID(),
(int)PWINDOW->m_bIsX11 ((int)PWINDOW->m_bIsX11 == 1 ? "true" : "false")
); );
} else { } 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", 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"; result += "\"keyboards\": [\n";
for (auto& k : g_pInputManager->m_lKeyboards) { 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( result += getFormat(
R"#( { R"#( {
"address": "0x%x", "address": "0x%x",
@@ -309,7 +310,8 @@ R"#( {
"layout": "%s", "layout": "%s",
"variant": "%s", "variant": "%s",
"options": "%s", "options": "%s",
"active_keymap": "%s" "active_keymap": "%s",
"main": %s
},)#", },)#",
&k, &k,
escapeJSONStrings(k.keyboard->name).c_str(), escapeJSONStrings(k.keyboard->name).c_str(),
@@ -318,7 +320,8 @@ R"#( {
escapeJSONStrings(k.currentRules.layout).c_str(), escapeJSONStrings(k.currentRules.layout).c_str(),
escapeJSONStrings(k.currentRules.variant).c_str(), escapeJSONStrings(k.currentRules.variant).c_str(),
escapeJSONStrings(k.currentRules.options).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"; result += "\n\nKeyboards:\n";
for (auto& k : g_pInputManager->m_lKeyboards) { 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("\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); 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"; result += "\n\nTablets:\n";
@@ -406,23 +409,56 @@ R"#( {
return result; return result;
} }
std::string versionRequest() { std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
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";
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 #ifdef LEGACY_RENDERER
result += "legacyrenderer\n"; result += "legacyrenderer\n";
#endif #endif
#ifndef NDEBUG #ifndef NDEBUG
result += "debug\n"; result += "debug\n";
#endif #endif
#ifdef HYPRLAND_DEBUG #ifdef HYPRLAND_DEBUG
result += "debug\n"; result += "debug\n";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
result += "no xwayland\n"; result += "no xwayland\n";
#endif #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) { std::string dispatchRequest(std::string in) {
@@ -457,8 +493,10 @@ std::string dispatchKeyword(std::string in) {
if (COMMAND == "monitor") if (COMMAND == "monitor")
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords 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->setKeyboardLayout(); // update kb layout
g_pInputManager->setMouseConfigs(); // update mouse cfgs
}
if (COMMAND.contains("general:layout")) if (COMMAND.contains("general:layout"))
g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout
@@ -471,9 +509,16 @@ std::string dispatchKeyword(std::string in) {
return retval; 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; g_pConfigManager->m_bForceReload = true;
if (REQMODE == "config-only") {
g_pConfigManager->m_bNoMonitorReload = true;
}
return "ok"; return "ok";
} }
@@ -521,6 +566,97 @@ std::string dispatchBatch(std::string request) {
return reply; 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) { std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL; auto format = HyprCtl::FORMAT_NORMAL;
@@ -555,9 +691,9 @@ std::string getReply(std::string request) {
else if (request == "layers") else if (request == "layers")
return layersRequest(format); return layersRequest(format);
else if (request == "version") else if (request == "version")
return versionRequest(); return versionRequest(format);
else if (request == "reload") else if (request.find("reload") == 0)
return reloadRequest(); return reloadRequest(request);
else if (request == "devices") else if (request == "devices")
return devicesRequest(format); return devicesRequest(format);
else if (request == "splash") else if (request == "splash")
@@ -566,6 +702,10 @@ std::string getReply(std::string request) {
return dispatchRequest(request); return dispatchRequest(request);
else if (request.find("keyword") == 0) else if (request.find("keyword") == 0)
return dispatchKeyword(request); 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) else if (request.find("[[BATCH]]") == 0)
return dispatchBatch(request); return dispatchBatch(request);
@@ -589,6 +729,10 @@ void HyprCtl::tickHyprCtl() {
requestMade = false; requestMade = false;
requestReady = true; requestReady = true;
if (g_pConfigManager->m_bWantsMonitorReload) {
g_pConfigManager->ensureDPMS();
}
} }
std::string getRequestFromThread(std::string rq) { std::string getRequestFromThread(std::string rq) {
@@ -663,4 +807,4 @@ void HyprCtl::startHyprCtlSocket() {
close(SOCKET); close(SOCKET);
}).detach(); }).detach();
} }

View File

@@ -12,6 +12,22 @@ void Debug::init(std::string IS) {
logFile = "/tmp/hypr/" + IS + "/hyprland.log"; logFile = "/tmp/hypr/" + IS + "/hyprland.log";
} }
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
char* outputStr = nullptr;
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
vasprintf(&outputStr, fmt, args);
std::string output = std::string(outputStr);
free(outputStr);
ofs << "[wlr] " << output << "\n";
ofs.close();
}
void Debug::log(LogLevel level, const char* fmt, ...) { void Debug::log(LogLevel level, const char* fmt, ...) {
if (disableLogs && *disableLogs) if (disableLogs && *disableLogs)

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <string> #include <string>
#include <wlr/util/log.h>
#define LOGMESSAGESIZE 1024 #define LOGMESSAGESIZE 1024
@@ -15,6 +16,7 @@ enum LogLevel {
namespace Debug { namespace Debug {
void init(std::string IS); void init(std::string IS);
void log(LogLevel level, const char* fmt, ...); void log(LogLevel level, const char* fmt, ...);
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
inline std::string logFile; inline std::string logFile;
inline int64_t* disableLogs = nullptr; inline int64_t* disableLogs = nullptr;

View File

@@ -72,7 +72,6 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
break; break;
case WLR_INPUT_DEVICE_TOUCH: case WLR_INPUT_DEVICE_TOUCH:
Debug::log(LOG, "Attached a touch device with name %s", DEVICE->name); 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); wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, DEVICE);
break; break;
case WLR_INPUT_DEVICE_TABLET_TOOL: 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) { void Events::listener_pinchEnd(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_pinch_end_event*)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); 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 // Power
LISTENER(powerMgrSetMode); 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_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"); 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) { 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->m_sDrag.hyprListener_destroy.removeCallback();
g_pInputManager->refocus(); 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) { 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)) if (!wlr_output_commit(EVENT->output))
Debug::log(ERR, "Couldn't set power mode"); 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; return;
} }
if (g_pCompositor->getMonitorFromName(std::string(OUTPUT->name))) { if (g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Monitor with name %s already exists, not adding as new!", OUTPUT->name); Debug::log(WARN, "Recovering from an unsafe state. May you be lucky.");
return;
} }
// add it to real // add it to real
const auto PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>()); std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
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->output = OUTPUT;
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP; PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
PNEWMONITOR->onConnect(false); PNEWMONITOR->onConnect(false);
if (!pMostHzMonitor || PNEWMONITOR->refreshRate > pMostHzMonitor->refreshRate) if ((!pMostHzMonitor || PNEWMONITOR->refreshRate > pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
pMostHzMonitor = PNEWMONITOR; pMostHzMonitor = PNEWMONITOR;
// ready to process cuz we have a monitor // 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) { void Events::listener_monitorFrame(void* owner, void* data) {
CMonitor* const PMONITOR = (CMonitor*)owner; 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!"); Debug::log(WARN, "Attempted to render frame on inactive session!");
return; // cannot draw on session inactive (different tty) return; // cannot draw on session inactive (different tty)
} }
@@ -293,20 +309,23 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
pMonitor->onDisconnect(); pMonitor->onDisconnect();
// cleanup // cleanup if not unsafe
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; }));
if (pMostHzMonitor == pMonitor) { if (!g_pCompositor->m_bUnsafeState) {
int mostHz = 0; 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; }));
CMonitor* pMonitorMostHz = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) { if (pMostHzMonitor == pMonitor) {
if (m->refreshRate > mostHz) { int mostHz = 0;
pMonitorMostHz = m.get(); CMonitor* pMonitorMostHz = nullptr;
mostHz = m->refreshRate;
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; 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); wlr_xdg_popup_unconstrain_from_box(popup, &box);
@@ -104,12 +104,9 @@ void Events::listener_newPopupXDG(void* owner, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
wlr_box geom;
wlr_xdg_surface_get_geometry(PWINDOW->m_uSurface.xdg, &geom);
PNEWPOPUP->popup = WLRPOPUP; PNEWPOPUP->popup = WLRPOPUP;
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x - geom.x; PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x;
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y - geom.y; PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y;
PNEWPOPUP->parentWindow = PWINDOW; PNEWPOPUP->parentWindow = PWINDOW;
PNEWPOPUP->monitor = PMONITOR; PNEWPOPUP->monitor = PMONITOR;
createNewPopup(WLRPOPUP, PNEWPOPUP); createNewPopup(WLRPOPUP, PNEWPOPUP);
@@ -151,7 +148,10 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0; int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly); 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 - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree); Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree);
} }
@@ -167,7 +167,10 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0; int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly); 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 - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
PPOPUP->pSurfaceTree = nullptr; 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); g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
// Foreign Toplevel // Foreign Toplevel
PWINDOW->m_phForeignToplevel = wlr_foreign_toplevel_handle_v1_create(g_pCompositor->m_sWLRToplevelMgr); PWINDOW->createToplevelHandle();
// TODO: handle foreign events (requests)
wlr_foreign_toplevel_handle_v1_set_app_id(PWINDOW->m_phForeignToplevel, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
// checks if the window wants borders and sets the appriopriate flag // checks if the window wants borders and sets the appriopriate flag
g_pXWaylandManager->checkBorders(PWINDOW); g_pXWaylandManager->checkBorders(PWINDOW);
@@ -87,6 +85,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bRequestsFloat = true; PWINDOW->m_bRequestsFloat = true;
} }
PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2);
if (PWORKSPACE->m_bDefaultFloating) if (PWORKSPACE->m_bDefaultFloating)
PWINDOW->m_bIsFloating = true; PWINDOW->m_bIsFloating = true;
@@ -107,7 +107,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW); const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
std::string requestedWorkspace = ""; std::string requestedWorkspace = "";
bool workspaceSilent = false; bool workspaceSilent = false;
bool requestsFullscreen = false; bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen);
for (auto& r : WINDOWRULES) { for (auto& r : WINDOWRULES) {
if (r.szRule.find("monitor") == 0) { if (r.szRule.find("monitor") == 0) {
@@ -118,13 +118,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_iMonitorID = PMONITOR->ID;
} else { } else {
const long int MONITOR = std::stoi(MONITORSTR); 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; PWINDOW->m_iMonitorID = 0;
else else
PWINDOW->m_iMonitorID = MONITOR; PWINDOW->m_iMonitorID = MONITOR;
} }
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace; 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); Debug::log(ERR, "Rule monitor, applying to window %x -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID);
} catch (std::exception& e) { } catch (std::exception& e) {
@@ -271,13 +272,13 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xdg->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xdg->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestMove.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_move, &Events::listener_requestMove, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_requestMove.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_move, &Events::listener_requestMove, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestResize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_resize, &Events::listener_requestResize, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_requestResize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_resize, &Events::listener_requestResize, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XDG Window Late");
} else { } else {
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XWayland Window Late");
PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW, "XWayland Window Late");
@@ -327,24 +328,31 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(g_pXWaylandManager->getWindowSurface(PWINDOW), addViewCoords, PWINDOW, PWINDOW); 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); 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);
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", getFormat("%x,%s,%s,%s", PWINDOW, workspaceID.c_str(), g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), PWINDOW->m_szTitle.c_str())});
} }
void Events::listener_unmapWindow(void* owner, void* data) { void Events::listener_unmapWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; CWindow* PWINDOW = (CWindow*)owner;
Debug::log(LOG, "Window %x unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str()); Debug::log(LOG, "Window %x unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%x", PWINDOW)});
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
Debug::log(LOG, "Unregistered late callbacks XDG"); Debug::log(LOG, "Unregistered late callbacks XDG");
PWINDOW->hyprListener_commitWindow.removeCallback(); PWINDOW->hyprListener_commitWindow.removeCallback();
PWINDOW->hyprListener_setTitleWindow.removeCallback(); PWINDOW->hyprListener_setTitleWindow.removeCallback();
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
PWINDOW->hyprListener_newPopupXDG.removeCallback(); PWINDOW->hyprListener_newPopupXDG.removeCallback();
PWINDOW->hyprListener_requestMaximize.removeCallback(); PWINDOW->hyprListener_requestMaximize.removeCallback();
PWINDOW->hyprListener_requestMinimize.removeCallback(); PWINDOW->hyprListener_requestMinimize.removeCallback();
PWINDOW->hyprListener_requestMove.removeCallback(); PWINDOW->hyprListener_requestMove.removeCallback();
PWINDOW->hyprListener_requestResize.removeCallback(); PWINDOW->hyprListener_requestResize.removeCallback();
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
} else { } else {
Debug::log(LOG, "Unregistered late callbacks XWL"); Debug::log(LOG, "Unregistered late callbacks XWL");
PWINDOW->hyprListener_fullscreenWindow.removeCallback(); PWINDOW->hyprListener_fullscreenWindow.removeCallback();
@@ -381,7 +389,22 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->m_bIsMapped = false; PWINDOW->m_bIsMapped = false;
// refocus on a new window // refocus on a new window
g_pInputManager->refocus(); auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f);
if (PWORKSPACE->m_bHasFullscreenWindow && (!PWINDOWCANDIDATE->m_bCreatedOverFullscreen || !PWINDOW->m_bIsFloating))
PWINDOWCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
if (!PWINDOWCANDIDATE || PWINDOW == PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bIsMapped || PWINDOWCANDIDATE->m_bHidden || PWINDOWCANDIDATE->m_bX11ShouldntFocus || PWINDOWCANDIDATE->m_iX11Type == 2 || PWINDOWCANDIDATE->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
PWINDOWCANDIDATE = nullptr;
Debug::log(LOG, "On closed window, new focused candidate is %x", PWINDOWCANDIDATE);
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow) {
if (!PWINDOWCANDIDATE)
g_pInputManager->refocus();
else
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
}
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %x", PWINDOW); Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %x", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree); SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
@@ -408,8 +431,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->m_fAlpha = 0.f; PWINDOW->m_fAlpha = 0.f;
// Destroy Foreign Toplevel // Destroy Foreign Toplevel
wlr_foreign_toplevel_handle_v1_destroy(PWINDOW->m_phForeignToplevel); PWINDOW->destroyToplevelHandle();
PWINDOW->m_phForeignToplevel = nullptr;
// recheck idle inhibitors // recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
@@ -465,8 +487,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 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}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle});
if (PWINDOW->m_phForeignToplevel) PWINDOW->updateToplevel();
wlr_foreign_toplevel_handle_v1_set_title(PWINDOW->m_phForeignToplevel, PWINDOW->m_szTitle.c_str());
Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str()); Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str());
} }
@@ -474,17 +495,27 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
void Events::listener_fullscreenWindow(void* owner, void* data) { void Events::listener_fullscreenWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bIsMapped) {
PWINDOW->m_bWantsInitialFullscreen = true;
return;
}
if (PWINDOW->m_bHidden)
return;
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested; const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested;
if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen) 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); wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
} else { } 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); Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen);
g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen); g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen);
@@ -511,7 +542,7 @@ void Events::listener_configureX11(void* owner, void* data) {
const auto E = (wlr_xwayland_surface_configure_event*)data; const auto E = (wlr_xwayland_surface_configure_event*)data;
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
if (!PWINDOW->m_bIsFloating) { if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec()); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec());
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW); 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) { void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) {
ASSERT(pSignal); ASSERT(pSignal);
ASSERT(pListener); ASSERT(pListener);
@@ -53,35 +75,6 @@ void handleNoop(struct wl_listener *listener, void *data) {
// Do nothing // 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, ...) { std::string getFormat(const char *fmt, ...) {
char* outputStr = nullptr; char* outputStr = nullptr;

View File

@@ -2,8 +2,8 @@
#include "../includes.hpp" #include "../includes.hpp"
std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, std::string ownerString); 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 getFormat(const char *fmt, ...); // Basically Debug::log to a string
std::string escapeJSONStrings(const std::string& str); std::string escapeJSONStrings(const std::string& str);
void scaleBox(wlr_box*, float); void scaleBox(wlr_box*, float);
@@ -17,4 +17,4 @@ std::string execAndGet(const char*);
float getPlusMinusKeywordResult(std::string in, float relative); 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" #include "../Compositor.hpp"
void CMonitor::onConnect(bool noRule) { void CMonitor::onConnect(bool noRule) {
if (m_bEnabled)
return;
szName = output->name;
// get monitor rule that matches // get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name); SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name);
@@ -11,22 +16,68 @@ void CMonitor::onConnect(bool noRule) {
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { 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_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(); hyprListener_monitorFrame.removeCallback();
return; 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()){ 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); g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
} }
m_bEnabled = true; m_bEnabled = true;
ID = g_pCompositor->getNextAvailableMonitorID();
szName = output->name;
wlr_output_set_scale(output, monitorRule.scale); wlr_output_set_scale(output, monitorRule.scale);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, 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 wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms
@@ -48,7 +99,7 @@ void CMonitor::onConnect(bool noRule) {
if (!noRule) if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); 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); damage = wlr_output_damage_create(output);
@@ -96,6 +147,8 @@ void CMonitor::onConnect(bool noRule) {
activeWorkspace = PNEWWORKSPACE->m_iID; activeWorkspace = PNEWWORKSPACE->m_iID;
scale = monitorRule.scale; scale = monitorRule.scale;
m_pThisWrap = nullptr;
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering. forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle); 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 if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->m_pLastMonitor = this; 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}); g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
} }
void CMonitor::onDisconnect() { void CMonitor::onDisconnect() {
if (!m_bEnabled)
return;
// Cleanup everything. Move windows back, snap cursor, shit. // Cleanup everything. Move windows back, snap cursor, shit.
CMonitor* BACKUPMON = nullptr; CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) { 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_bEnabled = false;
m_bRenderingInitPassed = false;
hyprListener_monitorFrame.removeCallback(); 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; const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;
// snap cursor // snap cursor
@@ -164,3 +232,11 @@ void CMonitor::onDisconnect() {
g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; })); g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; }));
} }
void CMonitor::addDamage(pixman_region32_t* rg) {
wlr_output_damage_add(damage, rg);
}
void CMonitor::addDamage(wlr_box* box) {
wlr_output_damage_add_box(damage, box);
}

View File

@@ -55,9 +55,12 @@ public:
// methods // methods
void onConnect(bool noRule); void onConnect(bool noRule);
void onDisconnect(); void onDisconnect();
void addDamage(pixman_region32_t* rg);
void addDamage(wlr_box* box);
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr; std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
// For the list lookup // For the list lookup

View File

@@ -94,11 +94,16 @@ struct SKeyboard {
DYNLISTENER(keyboardMod); DYNLISTENER(keyboardMod);
DYNLISTENER(keyboardKey); DYNLISTENER(keyboardKey);
DYNLISTENER(keyboardKeymap);
DYNLISTENER(keyboardDestroy); DYNLISTENER(keyboardDestroy);
bool isVirtual = false;
bool active = false; bool active = false;
xkb_layout_index_t activeLayout = 0;
std::string name = ""; std::string name = "";
std::string xkbFilePath = "";
SStringRuleNames currentRules; SStringRuleNames currentRules;
int repeatRate = 0; int repeatRate = 0;
@@ -272,4 +277,45 @@ struct SSwipeGesture {
int speedPoints = 0; int speedPoints = 0;
CMonitor* pMonitor = nullptr; 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;
Vector2D lastSize;
DYNLISTENER(mapPopup);
DYNLISTENER(unmapPopup);
DYNLISTENER(destroyPopup);
DYNLISTENER(commitPopup);
DYNLISTENER(focusedSurfaceUnmap);
bool operator==(const SIMEPopup& other) {
return pSurface == other.pSurface;
}
};

View File

@@ -18,6 +18,9 @@ public:
int m_iID = -1; int m_iID = -1;
std::string m_szName = ""; std::string m_szName = "";
uint64_t m_iMonitorID = -1; uint64_t m_iMonitorID = -1;
// Previous workspace ID is stored during a workspace change, allowing travel
// to the previous workspace.
int m_iPrevWorkspaceID = -1;
bool m_bHasFullscreenWindow = false; bool m_bHasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL; eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL;

View File

@@ -14,6 +14,8 @@ void CHyprError::createQueued() {
const auto PMONITOR = g_pCompositor->m_vMonitors.front().get(); 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 CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
const auto CAIRO = cairo_create(CAIROSURFACE); 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'); 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_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 // outline
cairo_rectangle(CAIRO, 0, 0, 1, PMONITOR->vecPixelSize.y); // left 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); 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_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); 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 != "") { while(m_szQueued != "") {
std::string current = m_szQueued.substr(0, m_szQueued.find('\n')); std::string current = m_szQueued.substr(0, m_szQueued.find('\n'));
if (const auto NEWLPOS = m_szQueued.find('\n'); NEWLPOS != std::string::npos) if (const auto NEWLPOS = m_szQueued.find('\n'); NEWLPOS != std::string::npos)
@@ -52,7 +54,7 @@ void CHyprError::createQueued() {
m_szQueued = ""; m_szQueued = "";
cairo_move_to(CAIRO, 0, yoffset); cairo_move_to(CAIRO, 0, yoffset);
cairo_show_text(CAIRO, current.c_str()); cairo_show_text(CAIRO, current.c_str());
yoffset += 9; yoffset += FONTSIZE + (FONTSIZE / 10.f);
} }

View File

@@ -32,6 +32,7 @@
#define class _class #define class _class
#define namespace _namespace #define namespace _namespace
#define static #define static
#define delete delete_
extern "C" { extern "C" {
#include <wlr/backend.h> #include <wlr/backend.h>
@@ -94,8 +95,12 @@ extern "C" {
#include <wlr/types/wlr_xdg_foreign_v2.h> #include <wlr/types/wlr_xdg_foreign_v2.h>
#include <wlr/types/wlr_pointer_gestures_v1.h> #include <wlr/types/wlr_pointer_gestures_v1.h>
#include <wlr/types/wlr_output_power_management_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 class
#undef namespace #undef namespace
#undef static #undef static

View File

@@ -1,24 +1,7 @@
#include "DwindleLayout.hpp" #include "DwindleLayout.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
void SDwindleNodeData::recalcSizePosRecursive() { void SDwindleNodeData::recalcSizePosRecursive(bool force) {
// 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;
}
if (children[0]) { if (children[0]) {
const auto REVERSESPLITRATIO = 2.f - splitRatio; 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[1]->size = Vector2D(size.x, size.y / 2.f * REVERSESPLITRATIO);
} }
children[0]->recalcSizePosRecursive(); children[0]->recalcSizePosRecursive(force);
children[1]->recalcSizePosRecursive(); children[1]->recalcSizePosRecursive(force);
} else { } 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 CHyprDwindleLayout::getNodesOnWorkspace(const int& id) {
int no = 0; int no = 0;
for (auto& n : m_lDwindleNodesData) { for (auto& n : m_lDwindleNodesData) {
@@ -94,7 +122,7 @@ SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const int& id) {
return nullptr; return nullptr;
} }
void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) { void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool force) {
// Don't set nodes, only windows. // Don't set nodes, only windows.
if (pNode->isNode) if (pNode->isNode)
return; return;
@@ -129,7 +157,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) {
const auto PWINDOW = pNode->pWindow; 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); Debug::log(ERR, "Node %x holding invalid window %x!!", pNode, PWINDOW);
return; return;
} }
@@ -143,17 +171,19 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) {
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE); auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) { if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) {
PWINDOW->m_vRealPosition = calcPos; PWINDOW->m_vRealPosition = calcPos - Vector2D(BORDERSIZE, BORDERSIZE);
PWINDOW->m_vRealSize = calcSize; PWINDOW->m_vRealSize = calcSize + Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
PWINDOW->m_sSpecialRenderData.rounding = false; PWINDOW->m_sSpecialRenderData.rounding = false;
PWINDOW->m_sSpecialRenderData.border = false;
return; return;
} }
PWINDOW->m_sSpecialRenderData.rounding = true; PWINDOW->m_sSpecialRenderData.rounding = true;
PWINDOW->m_sSpecialRenderData.border = true;
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN, const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN,
DISPLAYTOP ? GAPSOUT : GAPSIN); DISPLAYTOP ? GAPSOUT : GAPSIN);
@@ -203,6 +233,21 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) {
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize); g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
} }
if (force) {
PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealSize.warp();
g_pHyprRenderer->damageWindow(PWINDOW);
}
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(); PWINDOW->updateWindowDecos();
} }
@@ -215,6 +260,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); 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 // Populate the node with our window's data
PNODE->workspaceID = pWindow->m_iWorkspaceID; PNODE->workspaceID = pWindow->m_iWorkspaceID;
PNODE->pWindow = pWindow; PNODE->pWindow = pWindow;
@@ -224,13 +271,22 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
SDwindleNodeData* OPENINGON; SDwindleNodeData* OPENINGON;
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromCursor(); 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())); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
// happens on reserved area // happens on reserved area
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0) if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace); 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 } else
OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID); OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID);
@@ -241,6 +297,16 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
OPENINGON = getFirstNodeOnWorkspace(PNODE->workspaceID); 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 it's the first, it's easy. Make it fullscreen.
if (!OPENINGON || OPENINGON->pWindow == pWindow) { if (!OPENINGON || OPENINGON->pWindow == pWindow) {
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
@@ -250,6 +316,28 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
return; 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 // If it's not, get the node under our cursor
@@ -323,35 +411,66 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
OPENINGON->pParent = NEWPARENT; OPENINGON->pParent = NEWPARENT;
PNODE->pParent = NEWPARENT; PNODE->pParent = NEWPARENT;
if (OPENINGON->pGroupParent) { NEWPARENT->recalcSizePosRecursive();
// means we opened on a group
// add the group deco applyNodeDataToWindow(PNODE);
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow)); applyNodeDataToWindow(OPENINGON);
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);
}
} }
void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) { void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
const auto PNODE = getNodeFromWindow(pWindow); const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE) if (!PNODE) {
Debug::log(ERR, "onWindowRemovedTiling node null?");
return; 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; const auto PPARENT = PNODE->pParent;
if (!PPARENT) { if (!PPARENT) {
Debug::log(LOG, "Removing last node (dwindle)");
m_lDwindleNodesData.remove(*PNODE); m_lDwindleNodesData.remove(*PNODE);
return; return;
} }
@@ -370,29 +489,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; PPARENT->valid = false;
PNODE->valid = false; PNODE->valid = false;
@@ -407,6 +503,10 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
void CHyprDwindleLayout::recalculateMonitor(const int& monid) { void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
if (!PMONITOR)
return; // ???
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
if (!PWORKSPACE) if (!PWORKSPACE)
@@ -432,17 +532,21 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
// massive hack from the fullscreen func // massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
SDwindleNodeData fakeNode; if (!PFULLWINDOW) { // ????
fakeNode.pWindow = PFULLWINDOW; PWORKSPACE->m_bHasFullscreenWindow = false;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; } else {
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight; SDwindleNodeData fakeNode;
fakeNode.workspaceID = PWORKSPACE->m_iID; fakeNode.pWindow = PFULLWINDOW;
PFULLWINDOW->m_vPosition = fakeNode.position; fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
PFULLWINDOW->m_vSize = fakeNode.size; 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); const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace);
@@ -473,6 +577,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
return; return;
} }
const auto PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
// get some data about our window // get some data about our window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x); const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
@@ -504,11 +610,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
if (PARENTSIDEBYSIDE) { if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x; allowedMovement.x *= 2.f / PPARENT->size.x;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f); PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive(); PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else { } else {
allowedMovement.y *= 2.f / PPARENT->size.y; allowedMovement.y *= 2.f / PPARENT->size.y;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f); PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive(); PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} }
return; return;
@@ -523,11 +629,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
if (PARENTSIDEBYSIDE) { if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x; allowedMovement.x *= 2.f / PPARENT->size.x;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f); PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive(); PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else { } else {
allowedMovement.y *= 2.f / PPARENT->size.y; allowedMovement.y *= 2.f / PPARENT->size.y;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f); PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive(); PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} }
return; return;
@@ -542,14 +648,17 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f); 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); TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
SIDECONTAINER->recalcSizePosRecursive(); SIDECONTAINER->recalcSizePosRecursive(*PANIMATE == 0);
TOPCONTAINER->recalcSizePosRecursive(); TOPCONTAINER->recalcSizePosRecursive(*PANIMATE == 0);
} }
void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) { void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) {
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return; return;
if (!g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID))
return;
if (on == pWindow->m_bIsFullscreen) if (on == pWindow->m_bIsFullscreen)
return; // ignore return; // ignore
@@ -616,10 +725,6 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
g_pCompositor->moveWindowToTop(pWindow); 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); recalculateMonitor(PMONITOR->ID);
} }
@@ -632,6 +737,16 @@ void CHyprDwindleLayout::recalculateWindow(CWindow* pWindow) {
PNODE->recalcSizePosRecursive(); 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) { void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return; return;
@@ -642,61 +757,115 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
if (!PNODE) if (!PNODE)
return; // reject return; // reject
const auto PGROUPPARENT = PNODE->pGroupParent; const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNODE->workspaceID);
if (PGROUPPARENT) { if (PWORKSPACE->m_bHasFullscreenWindow)
// if there is a parent, release it fullscreenRequestForWindow(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), FULLSCREEN_FULL, false);
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
for (auto& wd : node->pWindow->m_dWindowDecorations) { if (PNODE->isGroupMember()) {
wd->updateWindow(node->pWindow); // 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)) PWINDOW->m_bHidden = false;
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"));
} }
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(); g_pInputManager->refocus();
} }
@@ -713,13 +882,13 @@ std::deque<CWindow*> CHyprDwindleLayout::getGroupMembers(CWindow* pWindow) {
if (!PNODE) if (!PNODE)
return result; // reject with empty return result; // reject with empty
const auto PGROUPPARENT = PNODE->pGroupParent; SDwindleNodeData* current = PNODE->pNextGroupMember;
if (!PGROUPPARENT) result.push_back(pWindow);
return result; // reject with empty
for (auto& node : PGROUPPARENT->groupMembers) { while (current != PNODE) {
result.push_back(node->pWindow); result.push_back(current->pWindow);
current = current->pNextGroupMember;
} }
return result; return result;
@@ -731,33 +900,41 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward) {
const auto PNODE = getNodeFromWindow(pWindow); const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE) if (!PNODE || !PNODE->isGroupMember())
return; // reject return; // reject
if (!PNODE->pGroupParent) const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNODE->workspaceID);
return; // reject
SDwindleNodeData* pNewNode;
if (forward) if (forward)
PNODE->pGroupParent->groupMemberActive++; pNewNode = PNODE->pNextGroupMember;
else else
PNODE->pGroupParent->groupMemberActive--; pNewNode = PNODE->pPreviousGroupMember;
if (PNODE->pGroupParent->groupMemberActive < 0) PNODE->setGroupFocusedNode(pNewNode);
PNODE->pGroupParent->groupMemberActive = PNODE->pGroupParent->groupMembers.size() - 1;
if ((long unsigned int)PNODE->pGroupParent->groupMemberActive >= PNODE->pGroupParent->groupMembers.size()) pNewNode->position = PNODE->position;
PNODE->pGroupParent->groupMemberActive = 0; pNewNode->size = PNODE->size;
PNODE->pGroupParent->recalcSizePosRecursive(); applyNodeDataToWindow(pNewNode);
for (auto& gm : PNODE->pGroupParent->groupMembers) { pNewNode->pWindow->m_vRealSize.warp();
for (auto& deco : gm->pWindow->m_dWindowDecorations) { pNewNode->pWindow->m_vRealPosition.warp();
deco->updateWindow(gm->pWindow);
} 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) { SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow) {
@@ -769,7 +946,7 @@ SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow
if (!PNODE) if (!PNODE)
return hints; // left for the future, maybe floating funkiness return hints; // left for the future, maybe floating funkiness
if (PNODE->pGroupParent) { if (PNODE->isGroupMember()) {
hints.isBorderColor = true; hints.isBorderColor = true;
if (pWindow == g_pCompositor->m_pLastWindow) if (pWindow == g_pCompositor->m_pLastWindow)
@@ -894,4 +1071,4 @@ void CHyprDwindleLayout::onEnable() {
void CHyprDwindleLayout::onDisable() { void CHyprDwindleLayout::onDisable() {
m_lDwindleNodesData.clear(); m_lDwindleNodesData.clear();
} }

View File

@@ -18,10 +18,9 @@ struct SDwindleNodeData {
bool splitTop = false; // for preserve_split bool splitTop = false; // for preserve_split
bool isGroup = false; bool groupHead = false;
int groupMemberActive = 0; SDwindleNodeData* pNextGroupMember = nullptr;
std::deque<SDwindleNodeData*> groupMembers; SDwindleNodeData* pPreviousGroupMember = nullptr;
SDwindleNodeData* pGroupParent = nullptr;
Vector2D position; Vector2D position;
Vector2D size; 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]; 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*>*); void getAllChildrenRecursive(std::deque<SDwindleNodeData*>*);
bool isGroupMember();
SDwindleNodeData* getGroupHead();
SDwindleNodeData* getGroupVisible();
void setGroupFocusedNode(SDwindleNodeData*);
CHyprDwindleLayout* layout = nullptr; CHyprDwindleLayout* layout = nullptr;
}; };
@@ -65,7 +68,7 @@ private:
std::list<SDwindleNodeData> m_lDwindleNodesData; std::list<SDwindleNodeData> m_lDwindleNodesData;
int getNodesOnWorkspace(const int&); int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SDwindleNodeData*); void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
SDwindleNodeData* getNodeFromWindow(CWindow*); SDwindleNodeData* getNodeFromWindow(CWindow*);
SDwindleNodeData* getFirstNodeOnWorkspace(const int&); SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
SDwindleNodeData* getMasterNodeOnWorkspace(const int&); SDwindleNodeData* getMasterNodeOnWorkspace(const int&);

View File

@@ -6,6 +6,16 @@ void IHyprLayout::onWindowCreated(CWindow* pWindow) {
if (pWindow->m_bIsFloating) { if (pWindow->m_bIsFloating) {
onWindowCreatedFloating(pWindow); onWindowCreatedFloating(pWindow);
} else { } 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); onWindowCreatedTiling(pWindow);
} }
} }
@@ -36,7 +46,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(pWindow); const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height); 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; pWindow->m_bHidden = true;
return; return;
} }
@@ -77,7 +87,6 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
if (pWindow->m_iX11Type != 2) { if (pWindow->m_iX11Type != 2) {
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
g_pCompositor->moveWindowToTop(pWindow); g_pCompositor->moveWindowToTop(pWindow);
} }
@@ -116,12 +125,14 @@ void IHyprLayout::onBeginDragWindow() {
changeWindowFloatingMode(DRAGGINGWINDOW); changeWindowFloatingMode(DRAGGINGWINDOW);
DRAGGINGWINDOW->m_bIsFloating = true; DRAGGINGWINDOW->m_bIsFloating = true;
DRAGGINGWINDOW->m_bDraggingTiled = true; DRAGGINGWINDOW->m_bDraggingTiled = true;
DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize.goalv() / 2.f;
} }
} }
m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal(); m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal();
m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.vec(); m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goalv();
m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.vec(); m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goalv();
m_vLastDragXY = m_vBeginDragXY; m_vLastDragXY = m_vBeginDragXY;
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); 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 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 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) if (abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f)
return; return;
@@ -166,16 +179,19 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (g_pInputManager->dragButton == BTN_LEFT) { if (g_pInputManager->dragButton == BTN_LEFT) {
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA); DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA);
DRAGGINGWINDOW->updateWindowDecos();
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
} else { } else {
if (DRAGGINGWINDOW->m_bIsFloating) { 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()); g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
} else { } else {
resizeActiveWindow(TICKDELTA, DRAGGINGWINDOW); resizeActiveWindow(TICKDELTA, DRAGGINGWINDOW);
@@ -190,9 +206,13 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (PMONITOR) { if (PMONITOR) {
DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID; DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID;
DRAGGINGWINDOW->m_iWorkspaceID = PMONITOR->activeWorkspace; DRAGGINGWINDOW->moveToWorkspace(PMONITOR->activeWorkspace);
DRAGGINGWINDOW->updateToplevel();
} }
DRAGGINGWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
} }
@@ -211,7 +231,7 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
if (!TILED) { if (!TILED) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f); const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID; pWindow->m_iMonitorID = PNEWMON->ID;
pWindow->m_iWorkspaceID = PNEWMON->activeWorkspace; pWindow->moveToWorkspace(PNEWMON->activeWorkspace);
// save real pos cuz the func applies the default 5,5 mid // save real pos cuz the func applies the default 5,5 mid
const auto PSAVEDPOS = pWindow->m_vRealPosition.vec(); const auto PSAVEDPOS = pWindow->m_vRealPosition.vec();
@@ -220,6 +240,8 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
// if the window is pseudo, update its size // if the window is pseudo, update its size
pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec(); pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec();
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
onWindowCreatedTiling(pWindow); onWindowCreatedTiling(pWindow);
pWindow->m_vRealPosition.setValue(PSAVEDPOS); pWindow->m_vRealPosition.setValue(PSAVEDPOS);
@@ -235,17 +257,17 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
g_pCompositor->moveWindowToTop(pWindow); g_pCompositor->moveWindowToTop(pWindow);
const auto POS = pWindow->m_vRealPosition.goalv(); pWindow->m_vRealPosition = pWindow->m_vRealPosition.vec() + (pWindow->m_vRealSize.vec() - pWindow->m_vLastFloatingSize) / 2.f;
const auto SIZ = pWindow->m_vRealSize.goalv(); pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
pWindow->m_vRealPosition.setValueAndWarp(POS + Vector2D(5, 5));
pWindow->m_vRealSize.setValueAndWarp(SIZ - Vector2D(10, 10));
pWindow->m_vRealPosition = POS;
pWindow->m_vRealSize = SIZ;
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); 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) { 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; 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(); const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back();
PNODE->workspaceID = pWindow->m_iWorkspaceID; PNODE->workspaceID = pWindow->m_iWorkspaceID;
@@ -60,8 +62,26 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
PNODE->isMaster = true; PNODE->isMaster = true;
PNODE->percMaster = lastSplitPercent; 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 { } else {
PNODE->isMaster = false; 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 // recalc
@@ -215,17 +235,19 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE); auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) { if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) {
PWINDOW->m_vRealPosition = calcPos; PWINDOW->m_vRealPosition = calcPos - Vector2D(BORDERSIZE, BORDERSIZE);
PWINDOW->m_vRealSize = calcSize; PWINDOW->m_vRealSize = calcSize + Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
PWINDOW->m_sSpecialRenderData.rounding = false; PWINDOW->m_sSpecialRenderData.rounding = false;
PWINDOW->m_sSpecialRenderData.border = false;
return; return;
} }
PWINDOW->m_sSpecialRenderData.rounding = true; PWINDOW->m_sSpecialRenderData.rounding = true;
PWINDOW->m_sSpecialRenderData.border = true;
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN, const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN,
DISPLAYTOP ? GAPSOUT : GAPSIN); DISPLAYTOP ? GAPSOUT : GAPSIN);
@@ -250,6 +272,13 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize); g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
} }
if (m_bForceWarps) {
PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealSize.warp();
g_pHyprRenderer->damageWindow(PWINDOW);
}
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
} }
@@ -278,6 +307,8 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2) if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2)
return; return;
m_bForceWarps = true;
float delta = pixResize.x / PMONITOR->vecSize.x; float delta = pixResize.x / PMONITOR->vecSize.x;
PMASTER->percMaster += delta; PMASTER->percMaster += delta;
@@ -285,12 +316,17 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
std::clamp(PMASTER->percMaster, 0.05f, 0.95f); std::clamp(PMASTER->percMaster, 0.05f, 0.95f);
recalculateMonitor(PMONITOR->ID); recalculateMonitor(PMONITOR->ID);
m_bForceWarps = false;
} }
void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) { void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) {
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return; return;
if (!g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID))
return;
if (on == pWindow->m_bIsFullscreen) if (on == pWindow->m_bIsFullscreen)
return; // ignore return; // ignore
@@ -357,10 +393,6 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
g_pCompositor->moveWindowToTop(pWindow); 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); recalculateMonitor(PMONITOR->ID);
} }

View File

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

View File

@@ -44,6 +44,10 @@ int main(int argc, char** argv) {
std::cout << "Welcome to Hyprland!\n"; std::cout << "Welcome to Hyprland!\n";
const auto LOGWLR = getenv("HYPRLAND_LOG_WLR");
if (LOGWLR && std::string(LOGWLR) == "1")
wlr_log_init(WLR_DEBUG, Debug::wlrLog);
// let's init the compositor. // let's init the compositor.
// it initializes basic Wayland stuff in the constructor. // it initializes basic Wayland stuff in the constructor.
g_pCompositor = std::make_unique<CCompositor>(); g_pCompositor = std::make_unique<CCompositor>();

View File

@@ -147,8 +147,8 @@ void CAnimationManager::tick() {
g_pHyprRenderer->damageBox(&WLRBOXPREV); g_pHyprRenderer->damageBox(&WLRBOXPREV);
if (PWINDOW) { if (PWINDOW) {
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW);
} else if (PWORKSPACE) { } else if (PWORKSPACE) {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_bHidden) if (!w->m_bIsMapped || w->m_bHidden)
@@ -197,7 +197,7 @@ void CAnimationManager::tick() {
if (PDECO) { if (PDECO) {
const auto EXTENTS = PDECO->getWindowDecorationExtents(); 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}; PWINDOW->m_vRealSize.vec().x + EXTENTS.topLeft.x + EXTENTS.bottomRight.x, PWINDOW->m_vRealSize.vec().y + EXTENTS.topLeft.y + EXTENTS.bottomRight.y};
if (!*PSHADOWIGNOREWINDOW) { 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; 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 // 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 GOALPOS = pWindow->m_vRealPosition.goalv();
const auto GOALSIZE = pWindow->m_vRealSize.goalv(); const auto GOALSIZE = pWindow->m_vRealSize.goalv();
if (!close) { if (!close) {
pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f); pWindow->m_vRealSize.setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}));
pWindow->m_vRealSize.setValue(Vector2D(5, 5)); pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_vValue / 2.f);
} else { } else {
pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f; pWindow->m_vRealSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y});
pWindow->m_vRealSize = Vector2D(5, 5); 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 { } else {
// anim popin, fallback // 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 { } else {
if (ANIMSTYLE == "slide") { if (ANIMSTYLE == "slide") {
animationSlide(pWindow, "", close); animationSlide(pWindow, "", close);
} else { } else {
// anim popin, fallback // 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); 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; std::list<CAnimatedVariable*> m_lAnimatedVariables;
private: private:
@@ -31,7 +35,7 @@ private:
std::unordered_map<std::string, CBezierCurve> m_mBezierCurves; std::unordered_map<std::string, CBezierCurve> m_mBezierCurves;
// Anim stuff // 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); void animationSlide(CWindow*, std::string force = "", bool close = false);
}; };

View File

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

View File

@@ -37,6 +37,8 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["layoutmsg"] = layoutmsg; m_mDispatchers["layoutmsg"] = layoutmsg;
m_mDispatchers["toggleopaque"] = toggleOpaque; m_mDispatchers["toggleopaque"] = toggleOpaque;
m_mDispatchers["dpms"] = dpms; m_mDispatchers["dpms"] = dpms;
m_mDispatchers["movewindowpixel"] = moveWindow;
m_mDispatchers["resizewindowpixel"] = resizeWindow;
m_tScrollTimer.reset(); m_tScrollTimer.reset();
} }
@@ -92,10 +94,51 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
return modMask; return modMask;
} }
void CKeybindManager::updateXKBTranslationState() {
if (m_pXKBTranslationState) {
xkb_keymap_unref(xkb_state_get_keymap(m_pXKBTranslationState));
xkb_state_unref(m_pXKBTranslationState);
m_pXKBTranslationState = nullptr;
}
const auto FILEPATH = g_pConfigManager->getString("input:kb_file");
const auto RULES = g_pConfigManager->getString("input:kb_rules");
const auto MODEL = g_pConfigManager->getString("input:kb_model");
const auto LAYOUT = g_pConfigManager->getString("input:kb_layout");
const auto VARIANT = g_pConfigManager->getString("input:kb_variant");
const auto OPTIONS = g_pConfigManager->getString("input:kb_options");
xkb_rule_names rules = {
.rules = RULES.c_str(),
.model = MODEL.c_str(),
.layout = LAYOUT.c_str(),
.variant = VARIANT.c_str(),
.options = OPTIONS.c_str()};
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
const auto PKEYMAP = FILEPATH == "" ? xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS) : xkb_keymap_new_from_file(PCONTEXT, fopen(FILEPATH.c_str(), "r"), XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_context_unref(PCONTEXT);
m_pXKBTranslationState = xkb_state_new(PKEYMAP);
}
bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) { bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
if (pKeyboard->isVirtual)
return true;
if (!m_pXKBTranslationState) {
Debug::log(ERR, "BUG THIS: m_pXKBTranslationState NULL!");
updateXKBTranslationState();
if (!m_pXKBTranslationState)
return true;
}
const auto KEYCODE = e->keycode + 8; // Because to xkbcommon it's +8 from libinput 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); const xkb_keysym_t keysym = xkb_state_key_get_one_sym(m_pXKBTranslationState, KEYCODE);
const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
@@ -257,6 +300,11 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
// call the dispatcher // call the dispatcher
Debug::log(LOG, "Keybind triggered, calling dispatcher (%d, %s, %d)", modmask, key.c_str(), keysym); Debug::log(LOG, "Keybind triggered, calling dispatcher (%d, %s, %d)", modmask, key.c_str(), keysym);
DISPATCHER->second(k.arg); DISPATCHER->second(k.arg);
if (k.handler == "submap") {
found = true; // don't process keybinds on submap change.
break;
}
} }
if (k.repeat) { if (k.repeat) {
@@ -405,14 +453,7 @@ void CKeybindManager::spawn(std::string args) {
} }
void CKeybindManager::killActive(std::string args) { void CKeybindManager::killActive(std::string args) {
if (g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow)) { g_pCompositor->closeWindow(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());
} }
void CKeybindManager::clearKeybinds() { void CKeybindManager::clearKeybinds() {
@@ -451,11 +492,34 @@ void CKeybindManager::changeworkspace(std::string args) {
int workspaceToChangeTo = 0; int workspaceToChangeTo = 0;
std::string workspaceName = ""; std::string workspaceName = "";
// Flag needed so that the previous workspace is not recorded when switching
// to a previous workspace.
bool isSwitchingToPrevious = false;
if (args.find("[internal]") == 0) { if (args.find("[internal]") == 0) {
workspaceToChangeTo = std::stoi(args.substr(10)); workspaceToChangeTo = std::stoi(args.substr(10));
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceToChangeTo); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceToChangeTo);
if (PWORKSPACE) if (PWORKSPACE)
workspaceName = PWORKSPACE->m_szName; workspaceName = PWORKSPACE->m_szName;
} else if (args.find("previous") == 0) {
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(
g_pCompositor->m_pLastMonitor->activeWorkspace);
// Do nothing if there's no previous workspace, otherwise switch to it.
if (PCURRENTWORKSPACE->m_iPrevWorkspaceID == -1) {
Debug::log(LOG, "No previous workspace to change to");
return;
}
else {
workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID;
isSwitchingToPrevious = true;
// If the previous workspace ID isn't reset, cycles can form when continually going
// to the previous workspace again and again.
static auto *const PALLOWWORKSPACECYCLES = &g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles")->intValue;
if (!*PALLOWWORKSPACECYCLES)
PCURRENTWORKSPACE->m_iPrevWorkspaceID = -1;
}
} else { } else {
workspaceToChangeTo = getWorkspaceIDFromString(args, workspaceName); workspaceToChangeTo = getWorkspaceIDFromString(args, workspaceName);
} }
@@ -465,8 +529,27 @@ void CKeybindManager::changeworkspace(std::string args) {
return; return;
} }
// Workspace_back_and_forth being enabled means that an attempt to switch to
// the current workspace will instead switch to the previous.
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(
g_pCompositor->m_pLastMonitor->activeWorkspace);
static auto *const PBACKANDFORTH = &g_pConfigManager->getConfigValuePtr("binds:workspace_back_and_forth")->intValue;
if (*PBACKANDFORTH
&& PCURRENTWORKSPACE->m_iID == workspaceToChangeTo
&& PCURRENTWORKSPACE->m_iPrevWorkspaceID != -1) {
workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID;
isSwitchingToPrevious = true;
// If the previous workspace ID isn't reset, cycles can form when continually going
// to the previous workspace again and again.
static auto *const PALLOWWORKSPACECYCLES = &g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles")->intValue;
if (!*PALLOWWORKSPACECYCLES)
PCURRENTWORKSPACE->m_iPrevWorkspaceID = -1;
}
// remove constraints // remove constraints
g_pCompositor->m_sSeat.mouse->constraintActive = false; g_pInputManager->unconstrainMouse();
// if it exists, we warp to it // if it exists, we warp to it
if (g_pCompositor->getWorkspaceByID(workspaceToChangeTo)) { if (g_pCompositor->getWorkspaceByID(workspaceToChangeTo)) {
@@ -474,6 +557,10 @@ void CKeybindManager::changeworkspace(std::string args) {
const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(workspaceToChangeTo); const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(workspaceToChangeTo);
if (!isSwitchingToPrevious)
// Remember previous workspace.
PWORKSPACETOCHANGETO->m_iPrevWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
if (workspaceToChangeTo == SPECIAL_WORKSPACE_ID) if (workspaceToChangeTo == SPECIAL_WORKSPACE_ID)
PWORKSPACETOCHANGETO->m_iMonitorID = PMONITOR->ID; PWORKSPACETOCHANGETO->m_iMonitorID = PMONITOR->ID;
@@ -487,13 +574,6 @@ void CKeybindManager::changeworkspace(std::string args) {
else else
PMONITOR->specialWorkspaceOpen = true; 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. // here and only here begin anim. we don't want to anim visible workspaces on other monitors.
// check if anim left or right // check if anim left or right
const auto ANIMTOLEFT = workspaceToChangeTo > OLDWORKSPACEID; const auto ANIMTOLEFT = workspaceToChangeTo > OLDWORKSPACEID;
@@ -545,6 +625,10 @@ void CKeybindManager::changeworkspace(std::string args) {
const auto PWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(PMONITOR->ID, workspaceName, workspaceToChangeTo == SPECIAL_WORKSPACE_ID)).get(); const auto PWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(PMONITOR->ID, workspaceName, workspaceToChangeTo == SPECIAL_WORKSPACE_ID)).get();
if (!isSwitchingToPrevious)
// Remember previous workspace.
PWORKSPACE->m_iPrevWorkspaceID = OLDWORKSPACE;
// start anim on new workspace // start anim on new workspace
PWORKSPACE->startAnim(true, ANIMTOLEFT); PWORKSPACE->startAnim(true, ANIMTOLEFT);
@@ -562,10 +646,6 @@ void CKeybindManager::changeworkspace(std::string args) {
else else
PMONITOR->specialWorkspaceOpen = true; 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 // set active and deactivate all other
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACE->m_pWlrHandle); g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACE->m_pWlrHandle);
PWORKSPACE->setActive(true); PWORKSPACE->setActive(true);
@@ -592,7 +672,15 @@ void CKeybindManager::fullscreenActive(std::string args) {
} }
void CKeybindManager::moveActiveToWorkspace(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)) if (!g_pCompositor->windowValidMapped(PWINDOW))
return; return;
@@ -629,7 +717,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
OLDWORKSPACE->m_bHasFullscreenWindow = false; OLDWORKSPACE->m_bHasFullscreenWindow = false;
PWINDOW->m_iWorkspaceID = PWORKSPACE->m_iID; PWINDOW->moveToWorkspace(PWORKSPACE->m_iID);
PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID; PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID;
PWINDOW->m_bIsFullscreen = false; PWINDOW->m_bIsFullscreen = false;
@@ -668,11 +756,27 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
} }
g_pInputManager->refocus(); g_pInputManager->refocus();
PWINDOW->updateToplevel();
} }
void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
// hacky, but works lol // 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; int workspaceToMoveTo = 0;
std::string workspaceName = ""; std::string workspaceName = "";
@@ -683,14 +787,9 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
return; return;
} }
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (workspaceToMoveTo == PMONITOR->activeWorkspace) if (workspaceToMoveTo == PWINDOW->m_iWorkspaceID)
return; return;
// may be null until later! // may be null until later!
@@ -706,7 +805,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
g_pEventManager->m_bIgnoreEvents = true; g_pEventManager->m_bIgnoreEvents = true;
moveActiveToWorkspace(args); moveActiveToWorkspace(ORIGINALARGS);
PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceToMoveTo); PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceToMoveTo);
@@ -738,13 +837,27 @@ void CKeybindManager::moveFocusTo(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
if (!PLASTWINDOW)
return;
// remove constraints // remove constraints
g_pCompositor->m_sSeat.mouse->constraintActive = false; g_pInputManager->unconstrainMouse();
auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) { auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) {
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f; if (PLASTWINDOW->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && PLASTWINDOW->m_bIsFullscreen) {
g_pCompositor->warpCursorTo(middle); 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)) { if (!g_pCompositor->windowValidMapped(PLASTWINDOW)) {
@@ -801,7 +914,7 @@ void CKeybindManager::moveActiveTo(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PLASTWINDOW)) if (!g_pCompositor->windowValidMapped(PLASTWINDOW) || PLASTWINDOW->m_bIsFullscreen)
return; return;
const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
@@ -1132,120 +1245,90 @@ void CKeybindManager::forceRendererReload(std::string args) {
} }
void CKeybindManager::resizeActive(std::string args) { void CKeybindManager::resizeActive(std::string args) {
if (!args.contains(' ')) if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return; return;
std::string x = args.substr(0, args.find_first_of(' ')); const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealSize.goalv());
std::string y = args.substr(args.find_first_of(' ') + 1);
if (x == "exact") { g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - g_pCompositor->m_pLastWindow->m_vRealSize.goalv());
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)) { if (g_pCompositor->m_pLastWindow->m_vRealSize.goalv().x > 1 && g_pCompositor->m_pLastWindow->m_vRealSize.goalv().y > 1)
Debug::log(ERR, "resizeTiledWindow: exact args not numbers"); g_pCompositor->m_pLastWindow->m_bHidden = false;
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));
} }
void CKeybindManager::moveActive(std::string args) { void CKeybindManager::moveActive(std::string args) {
if (!args.contains(' ')) if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return; return;
std::string x = args.substr(0, args.find_first_of(' ')); const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealPosition.goalv());
std::string y = args.substr(args.find_first_of(' ') + 1);
if (x == "exact") { g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - g_pCompositor->m_pLastWindow->m_vRealPosition.goalv());
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)) { void CKeybindManager::moveWindow(std::string args) {
Debug::log(ERR, "moveActive: exact args not numbers");
return;
}
const int X = std::stoi(newX); const auto WINDOWREGEX = args.substr(args.find_first_of(',') + 1);
const int Y = std::stoi(newY); const auto MOVECMD = args.substr(0, args.find_first_of(','));
if (X < 0 || Y < 0) { const auto PWINDOW = g_pCompositor->getWindowByRegex(WINDOWREGEX);
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));
if (!PWINDOW) {
Debug::log(ERR, "moveWindow: no window");
return; return;
} }
if (!isNumber(x) || !isNumber(y)) { const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goalv());
Debug::log(ERR, "moveActive: args not numbers");
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; return;
} }
const int X = std::stoi(x); const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goalv());
const int Y = std::stoi(y);
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) { void CKeybindManager::circleNext(std::string arg) {
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow)) if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return; 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) if (g_pCompositor->m_pLastWindow->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsFullscreen) {
return; 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") 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 else
g_pCompositor->focusWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow)); switchToWindow(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);
} }
void CKeybindManager::focusWindow(std::string regexp) { void CKeybindManager::focusWindow(std::string regexp) {
@@ -1305,6 +1388,9 @@ void CKeybindManager::pass(std::string regexp) {
// pass all mf shit // 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_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_PRESSED);
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_RELEASED); wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_RELEASED);

View File

@@ -69,6 +69,10 @@ private:
bool handleInternalKeybinds(xkb_keysym_t); bool handleInternalKeybinds(xkb_keysym_t);
bool handleVT(xkb_keysym_t); bool handleVT(xkb_keysym_t);
xkb_state* m_pXKBTranslationState = nullptr;
void updateXKBTranslationState();
// -------------- Dispatchers -------------- // // -------------- Dispatchers -------------- //
static void killActive(std::string); static void killActive(std::string);
static void spawn(std::string); static void spawn(std::string);
@@ -94,6 +98,8 @@ private:
static void forceRendererReload(std::string); static void forceRendererReload(std::string);
static void resizeActive(std::string); static void resizeActive(std::string);
static void moveActive(std::string); static void moveActive(std::string);
static void moveWindow(std::string);
static void resizeWindow(std::string);
static void circleNext(std::string); static void circleNext(std::string);
static void focusWindow(std::string); static void focusWindow(std::string);
static void setSubmap(std::string); static void setSubmap(std::string);

View File

@@ -32,9 +32,12 @@ wlr_surface* CHyprXWaylandManager::getWindowSurface(CWindow* pWindow) {
} }
void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) { void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) {
if (wlr_surface_is_xdg_surface(pSurface)) if (wlr_surface_is_xdg_surface(pSurface)) {
wlr_xdg_toplevel_set_activated(wlr_xdg_surface_from_wlr_surface(pSurface)->toplevel, activate); const auto PSURF = wlr_xdg_surface_from_wlr_surface(pSurface);
else if (wlr_surface_is_xwayland_surface(pSurface)) { if (PSURF->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
wlr_xdg_toplevel_set_activated(PSURF->toplevel, activate);
}
} else if (wlr_surface_is_xwayland_surface(pSurface)) {
wlr_xwayland_surface_activate(wlr_xwayland_surface_from_wlr_surface(pSurface), activate); wlr_xwayland_surface_activate(wlr_xwayland_surface_from_wlr_surface(pSurface), activate);
if (activate) if (activate)
@@ -120,9 +123,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; return;
pWindow->m_vReportedPosition = pWindow->m_vRealPosition.vec(); pWindow->m_vReportedPosition = pWindow->m_vRealPosition.vec();
@@ -155,8 +158,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_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_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
{ {
pWindow->m_bNoInitialFocus = 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"])
return true; pWindow->m_bX11ShouldntFocus = true;
pWindow->m_bNoInitialFocus = true;
return true;
} }
if (pWindow->m_uSurface.xwayland->role) { if (pWindow->m_uSurface.xwayland->role) {
@@ -230,4 +236,22 @@ void CHyprXWaylandManager::setWindowFullscreen(CWindow* pWindow, bool fullscreen
if (pWindow->m_phForeignToplevel) if (pWindow->m_phForeignToplevel)
wlr_foreign_toplevel_handle_v1_set_fullscreen(pWindow->m_phForeignToplevel, fullscreen); 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 getTitle(CWindow*);
std::string getAppIDClass(CWindow*); std::string getAppIDClass(CWindow*);
void sendCloseWindow(CWindow*); void sendCloseWindow(CWindow*);
void setWindowSize(CWindow*, const Vector2D&); void setWindowSize(CWindow*, const Vector2D&, bool force = false);
void setWindowStyleTiled(CWindow*, uint32_t); void setWindowStyleTiled(CWindow*, uint32_t);
void setWindowFullscreen(CWindow*, bool); void setWindowFullscreen(CWindow*, bool);
wlr_surface* surfaceAt(CWindow*, const Vector2D&, Vector2D&); wlr_surface* surfaceAt(CWindow*, const Vector2D&, Vector2D&);
bool shouldBeFloated(CWindow*); bool shouldBeFloated(CWindow*);
void moveXWaylandWindow(CWindow*, const Vector2D&); void moveXWaylandWindow(CWindow*, const Vector2D&);
void checkBorders(CWindow*); void checkBorders(CWindow*);
Vector2D getMaxSizeForWindow(CWindow*);
}; };
inline std::unique_ptr<CHyprXWaylandManager> g_pXWaylandManager; inline std::unique_ptr<CHyprXWaylandManager> g_pXWaylandManager;

View File

@@ -29,7 +29,10 @@ void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) {
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue; 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;
static auto *const PFLOATBEHAVIOR = &g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus")->intValue;
if (!g_pCompositor->m_bReadyToProcess) if (!g_pCompositor->m_bReadyToProcess)
return; return;
@@ -67,7 +70,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse); const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
if (!CONSTRAINTWINDOW) { if (!CONSTRAINTWINDOW) {
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr; unconstrainMouse();
} else { } else {
// Native Wayland apps know how 2 constrain themselves. // Native Wayland apps know how 2 constrain themselves.
// XWayland, we just have to accept them. Might cause issues, but thats XWayland for ya. // XWayland, we just have to accept them. Might cause issues, but thats XWayland for ya.
@@ -123,7 +126,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
ACTIVEWORKSPACE->setActive(true); ACTIVEWORKSPACE->setActive(true);
// event // event
g_pEventManager->postEvent(SHyprIPCEvent{"activemon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName}); g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName});
} }
Vector2D surfaceCoords; Vector2D surfaceCoords;
@@ -180,11 +183,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen)) if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen))
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
} }
} else } else {
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (!pFoundWindow && refocus) // TODO: this causes crashes, sometimes. ???
pFoundWindow = g_pCompositor->getFirstWindowOnWorkspace(PWORKSPACE->m_iID); // if (refocus && !pFoundWindow) {
// pFoundWindow = g_pCompositor->getFirstWindowOnWorkspace(PMONITOR->activeWorkspace);
// }
}
if (pFoundWindow) { if (pFoundWindow) {
if (!pFoundWindow->m_bIsX11) { if (!pFoundWindow->m_bIsX11) {
@@ -212,9 +218,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat); 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! 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->focusWindow(nullptr);
g_pCompositor->m_pLastWindow = nullptr;
} }
return; return;
@@ -233,11 +237,21 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
surfaceLocal = mouseCoords - surfacePos + Vector2D(geom.x, geom.y); 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 (pFoundWindow) {
if (*PFOLLOWMOUSE != 1 && !refocus) { 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)) { if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR) {
// enter if change floating style // enter if change floating style
if (*PFOLLOWMOUSE != 3) if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface); g_pCompositor->focusWindow(pFoundWindow, foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} else if (*PFOLLOWMOUSE == 2) { } else if (*PFOLLOWMOUSE == 2) {
@@ -249,14 +263,22 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); 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); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
return; // don't enter any new surfaces return; // don't enter any new surfaces
} else { } else {
if (*PFOLLOWMOUSE != 3) if ((*PFOLLOWMOUSE != 3 && allowKeyboardRefocus) || refocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface); g_pCompositor->focusWindow(pFoundWindow, foundSurface);
} }
} else if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3) } else {
g_pCompositor->focusSurface(foundSurface); 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_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); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
@@ -315,7 +337,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
m_ecbClickBehavior = CLICKMODE_KILL; m_ecbClickBehavior = CLICKMODE_KILL;
// remove constraints // remove constraints
g_pCompositor->m_sSeat.mouse->constraintActive = false; g_pInputManager->unconstrainMouse();
refocus(); refocus();
// set cursor // set cursor
@@ -428,10 +450,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_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_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard");
if (m_pActiveKeyboard) PNEWKEYBOARD->hyprListener_keyboardKeymap.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.keymap, [&](void* owner, void* data) {
m_pActiveKeyboard->active = false; 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; m_pActiveKeyboard = PNEWKEYBOARD;
PNEWKEYBOARD->active = true;
applyConfigToKeyboard(PNEWKEYBOARD); applyConfigToKeyboard(PNEWKEYBOARD);
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(keyboard)); wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(keyboard));
@@ -439,9 +470,46 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
Debug::log(LOG, "New keyboard created, pointers Hypr: %x and WLR: %x", PNEWKEYBOARD, 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() { void CInputManager::setKeyboardLayout() {
for (auto& k : m_lKeyboards) for (auto& k : m_lKeyboards)
applyConfigToKeyboard(&k); applyConfigToKeyboard(&k);
g_pKeybindManager->updateXKBTranslationState();
} }
void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
@@ -462,6 +530,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 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 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 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"); const auto LAYOUT = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_layout") : g_pConfigManager->getString("input:kb_layout");
@@ -469,7 +538,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
const auto OPTIONS = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_options") : g_pConfigManager->getString("input:kb_options"); const auto OPTIONS = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_options") : g_pConfigManager->getString("input:kb_options");
try { 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."); Debug::log(LOG, "Not applying config to keyboard, it did not change.");
return; return;
} }
@@ -483,6 +552,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
pKeyboard->repeatDelay = REPEATDELAY; pKeyboard->repeatDelay = REPEATDELAY;
pKeyboard->repeatRate = REPEATRATE; pKeyboard->repeatRate = REPEATRATE;
pKeyboard->numlockOn = NUMLOCKON; pKeyboard->numlockOn = NUMLOCKON;
pKeyboard->xkbFilePath = FILEPATH.c_str();
xkb_rule_names rules = { xkb_rule_names rules = {
.rules = RULES.c_str(), .rules = RULES.c_str(),
@@ -506,9 +576,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); 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) { 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); 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)); memset(&rules, 0, sizeof(rules));
@@ -540,6 +626,8 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
xkb_keymap_unref(KEYMAP); xkb_keymap_unref(KEYMAP);
xkb_context_unref(CONTEXT); 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); 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 +749,7 @@ void CInputManager::destroyMouse(wlr_input_device* mouse) {
g_pCompositor->m_sSeat.mouse = m_lMice.size() > 0 ? &m_lMice.front() : nullptr; g_pCompositor->m_sSeat.mouse = m_lMice.size() > 0 ? &m_lMice.front() : nullptr;
if (g_pCompositor->m_sSeat.mouse) if (g_pCompositor->m_sSeat.mouse)
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr; unconstrainMouse();
} }
void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) { void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
@@ -670,14 +758,37 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat); wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
if (passEvent) { 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) { void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard)); const auto PIMEGRAB = m_sIMERelay.getIMEKeyboardGrab(pKeyboard);
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers);
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() { void CInputManager::refocus() {
@@ -685,16 +796,16 @@ void CInputManager::refocus() {
} }
void CInputManager::updateDragIcon() { void CInputManager::updateDragIcon() {
if (!g_pInputManager->m_sDrag.dragIcon) if (!m_sDrag.dragIcon)
return; return;
switch (g_pInputManager->m_sDrag.dragIcon->drag->grab_type) { switch (m_sDrag.dragIcon->drag->grab_type) {
case WLR_DRAG_GRAB_KEYBOARD: case WLR_DRAG_GRAB_KEYBOARD:
break; break;
case WLR_DRAG_GRAB_KEYBOARD_POINTER: { 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_pHyprRenderer->damageBox(&box);
g_pInputManager->m_sDrag.pos = g_pInputManager->getMouseCoordsInternal(); m_sDrag.pos = getMouseCoordsInternal();
break; break;
} }
default: default:
@@ -773,6 +884,29 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
Debug::log(LOG, "Constrained mouse to %x", pMouse->currentConstraint); 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) { void Events::listener_commitConstraint(void* owner, void* data) {
//g_pInputManager->recheckConstraint((SMouse*)owner); //g_pInputManager->recheckConstraint((SMouse*)owner);
} }
@@ -807,3 +941,32 @@ uint32_t CInputManager::accumulateModsFromAllKBs() {
return finalMask; 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 "../../helpers/WLClasses.hpp"
#include "../../Window.hpp" #include "../../Window.hpp"
#include "../../helpers/Timer.hpp" #include "../../helpers/Timer.hpp"
#include "InputMethodRelay.hpp"
enum eClickBehaviorMode { enum eClickBehaviorMode {
CLICKMODE_DEFAULT = 0, CLICKMODE_DEFAULT = 0,
CLICKMODE_KILL CLICKMODE_KILL
}; };
struct STouchData {
CWindow* touchFocusWindow = nullptr;
Vector2D touchSurfaceOrigin;
};
class CInputManager { class CInputManager {
public: public:
@@ -22,12 +28,15 @@ public:
void onKeyboardMod(void*, SKeyboard*); void onKeyboardMod(void*, SKeyboard*);
void newKeyboard(wlr_input_device*); void newKeyboard(wlr_input_device*);
void newVirtualKeyboard(wlr_input_device*);
void newMouse(wlr_input_device*, bool virt = false); void newMouse(wlr_input_device*, bool virt = false);
void destroyKeyboard(SKeyboard*); void destroyKeyboard(SKeyboard*);
void destroyMouse(wlr_input_device*); void destroyMouse(wlr_input_device*);
void constrainMouse(SMouse*, wlr_pointer_constraint_v1*); void constrainMouse(SMouse*, wlr_pointer_constraint_v1*);
void recheckConstraint(SMouse*); void recheckConstraint(SMouse*);
void unconstrainMouse();
std::string getActiveLayoutForKeyboard(SKeyboard*);
Vector2D getMouseCoordsInternal(); Vector2D getMouseCoordsInternal();
void refocus(); void refocus();
@@ -42,6 +51,11 @@ public:
eClickBehaviorMode getClickMode(); eClickBehaviorMode getClickMode();
void processMouseRequest(wlr_seat_pointer_request_set_cursor_event*); 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 // for dragging floating windows
CWindow* currentlyDraggedWindow = nullptr; CWindow* currentlyDraggedWindow = nullptr;
@@ -77,9 +91,13 @@ public:
CTimer m_tmrLastCursorMovement; CTimer m_tmrLastCursorMovement;
CInputMethodRelay m_sIMERelay;
// for shared mods // for shared mods
uint32_t accumulateModsFromAllKBs(); uint32_t accumulateModsFromAllKBs();
CWindow* m_pFollowOnDnDBegin = nullptr;
private: private:
// for click behavior override // for click behavior override
@@ -89,6 +107,8 @@ private:
void processMouseDownNormal(wlr_pointer_button_event* e); void processMouseDownNormal(wlr_pointer_button_event* e);
void processMouseDownKill(wlr_pointer_button_event* e); void processMouseDownKill(wlr_pointer_button_event* e);
void disableAllKeyboards(bool virt = false);
uint32_t m_uiCapabilities = 0; uint32_t m_uiCapabilities = 0;
void mouseMoveUnified(uint32_t, bool refocus = false); void mouseMoveUnified(uint32_t, bool refocus = false);

View File

@@ -0,0 +1,451 @@
#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;
// damage last known pos & size
g_pHyprRenderer->damageBox(pPopup->realX, pPopup->realY, pPopup->lastSize.x, pPopup->lastSize.y);
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;
pPopup->lastSize = Vector2D(pPopup->pSurface->surface->current.width, pPopup->pSurface->surface->current.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_pHyprRenderer->damageBox(PPOPUP->realX, PPOPUP->realY, PPOPUP->lastSize.x, PPOPUP->lastSize.y);
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;
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_vRenderOffset = Vector2D(m_sActiveSwipe.pMonitor->vecSize.x, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f); 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"); Debug::log(LOG, "Ended swipe to the left");
} else { } 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_vRenderOffset = Vector2D(-m_sActiveSwipe.pMonitor->vecSize.x, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f); 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"); Debug::log(LOG, "Ended swipe to the right");
} }
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
PWORKSPACEL->m_bForceRendering = false; PWORKSPACEL->m_bForceRendering = false;
PWORKSPACER->m_bForceRendering = false; PWORKSPACER->m_bForceRendering = false;
m_sActiveSwipe.pWorkspaceBegin->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); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
PWORKSPACE->m_bForceRendering = true; PWORKSPACE->m_bForceRendering = true;
PWORKSPACE->m_fAlpha.setValueAndWarp(255.f);
if (workspaceIDLeft != workspaceIDRight) { if (workspaceIDLeft != workspaceIDRight) {
const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight);
PWORKSPACER->m_bForceRendering = false; 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)); 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); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight);
PWORKSPACE->m_bForceRendering = true; PWORKSPACE->m_bForceRendering = true;
PWORKSPACE->m_fAlpha.setValueAndWarp(255.f);
if (workspaceIDLeft != workspaceIDRight) { if (workspaceIDLeft != workspaceIDRight) {
const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
PWORKSPACEL->m_bForceRendering = false; 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)); 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!"); Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!");
#endif #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 // End shaders
pixman_region32_init(&m_rOriginalDamageRegion); 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) { void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool fake) {
m_RenderData.pMonitor = pMonitor; 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); glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); 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); createBGTextureForMonitor(pMonitor);
} }
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
initShaders();
// bind the primary Hypr Framebuffer // bind the primary Hypr Framebuffer
m_RenderData.pCurrentMonData->primaryFB.bind(); m_RenderData.pCurrentMonData->primaryFB.bind();
@@ -236,6 +139,112 @@ void CHyprOpenGLImpl::end() {
m_iWLROutputFb = 0; 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) { void CHyprOpenGLImpl::clear(const CColor& color) {
RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!"); 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); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 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); glUniformMatrix3fv(m_RenderData.pCurrentMonData->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); 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 TOPLEFT = Vector2D(round, round);
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - 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; static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
// Rounded corners // Rounded corners
glUniform2f(m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shQUAD.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shQUAD.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.radius, round);
glUniform1i(m_shQUAD.primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0)); 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_RenderData.pCurrentMonData->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.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shQUAD.posAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib);
glEnableVertexAttribArray(m_shQUAD.texAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.texAttrib);
if (pixman_region32_not_empty(damage)) { if (pixman_region32_not_empty(damage)) {
PIXMAN_DAMAGE_FOREACH(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_RenderData.pCurrentMonData->m_shQUAD.posAttrib);
glDisableVertexAttribArray(m_shQUAD.texAttrib); glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.texAttrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} }
@@ -385,13 +394,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
switch (tex.m_iType) { switch (tex.m_iType) {
case TEXTURE_RGBA: case TEXTURE_RGBA:
shader = &m_shRGBA; shader = &m_RenderData.pCurrentMonData->m_shRGBA;
break; break;
case TEXTURE_RGBX: case TEXTURE_RGBX:
shader = &m_shRGBX; shader = &m_RenderData.pCurrentMonData->m_shRGBX;
break; break;
case TEXTURE_EXTERNAL: case TEXTURE_EXTERNAL:
shader = &m_shEXT; shader = &m_RenderData.pCurrentMonData->m_shEXT;
break; break;
default: default:
RASSERT(false, "tex.m_iTarget unsupported!"); RASSERT(false, "tex.m_iTarget unsupported!");
@@ -510,10 +519,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
// prep two shaders // prep two shaders
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
glUniform1f(pShader->radius, *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a glUniform1f(pShader->radius, *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a
if (pShader == &m_shBLUR1) if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1)
glUniform2f(m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); 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 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); glUniform1i(pShader->tex, 0);
glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); 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); 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 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 // and draw
for (int i = 1; i < *PBLURPASSES; ++i) { for (int i = 1; i < *PBLURPASSES; ++i) {
wlr_region_scale(&tempDamage, &damage, 1.f / (1 << (i + 1))); 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) { 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 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 // finish
@@ -676,7 +685,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
} }
// vvv TODO: layered blur fbs? // vvv TODO: layered blur fbs?
const bool USENEWOPTIMIZE = (*PBLURNEWOPTIMIZE && m_pCurrentWindow && !m_pCurrentWindow->m_bIsFloating && m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID); const bool USENEWOPTIMIZE = (*PBLURNEWOPTIMIZE && m_pCurrentWindow && !m_pCurrentWindow->m_bIsFloating && m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID && m_pCurrentWindow->m_iWorkspaceID != SPECIAL_WORKSPACE_ID);
const auto POUTFB = USENEWOPTIMIZE ? &m_RenderData.pCurrentMonData->blurFB : blurMainFramebufferWithDamage(a, pBox, &inverseOpaque); const auto POUTFB = USENEWOPTIMIZE ? &m_RenderData.pCurrentMonData->blurFB : blurMainFramebufferWithDamage(a, pBox, &inverseOpaque);
@@ -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 PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto *const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->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 // adjust box
box->x -= *PBORDERSIZE; box->x -= *PBORDERSIZE;
box->y -= *PBORDERSIZE; box->y -= *PBORDERSIZE;
@@ -761,27 +787,27 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 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); glUniformMatrix3fv(m_RenderData.pCurrentMonData->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); 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 TOPLEFT = Vector2D(round, round);
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round); const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round);
const auto FULLSIZE = Vector2D(box->width, box->height); const auto FULLSIZE = Vector2D(box->width, box->height);
glUniform2f(m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shBORDER1.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round);
glUniform1f(m_shBORDER1.thick, *PBORDERSIZE); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, *PBORDERSIZE);
glUniform1i(m_shBORDER1.primitiveMultisample, *PMULTISAMPLE); glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample, *PMULTISAMPLE);
glVertexAttribPointer(m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(m_RenderData.pCurrentMonData->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.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shBORDER1.posAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib);
glEnableVertexAttribArray(m_shBORDER1.texAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) { if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(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_RenderData.pCurrentMonData->m_shBORDER1.posAttrib);
glDisableVertexAttribArray(m_shBORDER1.texAttrib); glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} }
@@ -870,7 +896,7 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
// this is temporary, doesnt mess with the actual wlr damage // this is temporary, doesnt mess with the actual wlr damage
pixman_region32_t fakeDamage; pixman_region32_t fakeDamage;
pixman_region32_init(&fakeDamage); pixman_region32_init(&fakeDamage);
pixman_region32_union_rect(&fakeDamage, &fakeDamage, 0, 0, (int)PMONITOR->vecPixelSize.x, (int)PMONITOR->vecPixelSize.y); pixman_region32_union_rect(&fakeDamage, &fakeDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
begin(PMONITOR, &fakeDamage, true); begin(PMONITOR, &fakeDamage, true);
@@ -890,8 +916,6 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
// draw the layer // draw the layer
g_pHyprRenderer->renderLayer(pLayer, PMONITOR, &now); g_pHyprRenderer->renderLayer(pLayer, PMONITOR, &now);
m_bEndFrame = false;
// TODO: WARN: // TODO: WARN:
// revise if any stencil-requiring rendering is done to the layers. // revise if any stencil-requiring rendering is done to the layers.
@@ -966,12 +990,16 @@ void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PLAYER->monitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PLAYER->monitorID);
wlr_box windowBox = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y}; wlr_box monbox = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
pixman_region32_t fakeDamage; pixman_region32_t fakeDamage;
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y); pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y);
renderTextureInternalWithDamage(it->second.m_cTex, &windowBox, PLAYER->alpha.fl(), &fakeDamage, 0); m_bEndFrame = true;
renderTextureInternalWithDamage(it->second.m_cTex, &monbox, PLAYER->alpha.fl(), &fakeDamage, 0);
m_bEndFrame = false;
pixman_region32_fini(&fakeDamage); pixman_region32_fini(&fakeDamage);
@@ -1004,28 +1032,28 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 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); glUniformMatrix3fv(m_RenderData.pCurrentMonData->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); 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 TOPLEFT = Vector2D(range + round, range + round);
const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round)); const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round));
const auto FULLSIZE = Vector2D(box->width, box->height); const auto FULLSIZE = Vector2D(box->width, box->height);
// Rounded corners // Rounded corners
glUniform2f(m_shSHADOW.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shSHADOW.radius, range + round); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.radius, range + round);
glUniform1f(m_shSHADOW.range, range); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.range, range);
glUniform1f(m_shSHADOW.shadowPower, SHADOWPOWER); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower, SHADOWPOWER);
glVertexAttribPointer(m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(m_RenderData.pCurrentMonData->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.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shSHADOW.posAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib);
glEnableVertexAttribArray(m_shSHADOW.texAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) { if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
@@ -1035,8 +1063,8 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
} }
} }
glDisableVertexAttribArray(m_shSHADOW.posAttrib); glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib);
glDisableVertexAttribArray(m_shSHADOW.texAttrib); glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} }
@@ -1081,10 +1109,10 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
// get the adequate tex // get the adequate tex
std::string texPath = "/usr/share/hyprland/wall_"; std::string texPath = "/usr/share/hyprland/wall_";
Vector2D textureSize; Vector2D textureSize;
if (pMonitor->vecTransformedSize.x > 7000) { if (pMonitor->vecTransformedSize.x > 3850) {
textureSize = Vector2D(7680, 4320); textureSize = Vector2D(7680, 4320);
texPath += "8K.png"; texPath += "8K.png";
} else if (pMonitor->vecTransformedSize.x > 3000) { } else if (pMonitor->vecTransformedSize.x > 1930) {
textureSize = Vector2D(3840, 2160); textureSize = Vector2D(3840, 2160);
texPath += "4K.png"; texPath += "4K.png";
} else { } else {
@@ -1105,8 +1133,8 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
// copy the data to an OpenGL texture we have // copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
glBindTexture(GL_TEXTURE_2D, PTEX->m_iTexID); glBindTexture(GL_TEXTURE_2D, PTEX->m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#ifndef GLES2 #ifndef GLES2
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);

View File

@@ -42,6 +42,18 @@ struct SMonitorRenderData {
bool blurFBDirty = true; bool blurFBDirty = true;
wlr_box backgroundTexBox; 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 { struct SCurrentRenderData {
@@ -114,20 +126,10 @@ private:
bool m_bFakeFrame = false; bool m_bFakeFrame = false;
bool m_bEndFrame = 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 createProgram(const std::string&, const std::string&);
GLuint compileShader(const GLuint&, std::string); GLuint compileShader(const GLuint&, std::string);
void createBGTextureForMonitor(CMonitor*); void createBGTextureForMonitor(CMonitor*);
void initShaders();
// returns the out FB, can be either Mirror or MirrorSwap // returns the out FB, can be either Mirror or MirrorSwap
CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage); CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage);

View File

@@ -32,10 +32,11 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
scaleBox(&windowBox, RDATA->output->scale); scaleBox(&windowBox, RDATA->output->scale);
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; 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; float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? *PROUNDING : RDATA->rounding;
rounding += *PBORDERTHICK; rounding *= RDATA->output->scale;
rounding -= 1; // to fix a border issue
if (RDATA->surface && surface == RDATA->surface) { 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) { if (wlr_surface_is_xwayland_surface(surface) && !wlr_xwayland_surface_from_wlr_surface(surface)->has_alpha && RDATA->fadeAlpha * RDATA->alpha == 255.f) {
@@ -80,16 +81,22 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID) { if (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID) {
if (!(!PWORKSPACE->m_bHasFullscreenWindow || pWindow->m_bIsFullscreen || (pWindow->m_bIsFloating && pWindow->m_bCreatedOverFullscreen))) if (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()) {
return false; return true;
} else {
if (!(!PWORKSPACE->m_bHasFullscreenWindow || pWindow->m_bIsFullscreen || (pWindow->m_bIsFloating && pWindow->m_bCreatedOverFullscreen)))
return false;
}
} }
if (pWindow->m_iWorkspaceID == pMonitor->activeWorkspace) if (pWindow->m_iWorkspaceID == pMonitor->activeWorkspace)
return true; return true;
// if not, check if it maybe is active on a different monitor. vvv might be animation in progress // 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) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))) if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) ||
return true; (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) if (pMonitor->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
return true; return true;
@@ -127,6 +134,9 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen){ if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen){
if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))) if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
continue; continue;
if (w->m_iMonitorID != pMonitor->ID)
continue;
} }
if (w->m_iWorkspaceID == pMonitor->activeWorkspace && !w->m_bIsFullscreen) if (w->m_iWorkspaceID == pMonitor->activeWorkspace && !w->m_bIsFullscreen)
@@ -256,10 +266,11 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata); 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; static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding; float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding;
rounding *= pMonitor->scale;
auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col(); auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col();
col.a *= renderdata.fadeAlpha * renderdata.alpha / 255.f; col.a *= renderdata.fadeAlpha * renderdata.alpha / 255.f;
@@ -277,7 +288,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) { if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) {
if (!pWindow->m_bIsX11) { if (!pWindow->m_bIsX11) {
renderdata.dontRound = false; // restore dontround renderdata.dontRound = true; // don't round popups
renderdata.pMonitor = pMonitor; renderdata.pMonitor = pMonitor;
renderdata.squishOversized = false; // don't squish popups renderdata.squishOversized = false; // don't squish popups
wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata); wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata);
@@ -303,9 +314,22 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata); wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
renderdata.squishOversized = false; // don't squish popups renderdata.squishOversized = false; // don't squish popups
renderdata.dontRound = true;
wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata); 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) { void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(ID); const auto PMONITOR = g_pCompositor->getMonitorFromID(ID);
@@ -405,6 +429,12 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
renderLayer(ls.get(), PMONITOR, time); 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]) { for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
renderLayer(ls.get(), PMONITOR, time); renderLayer(ls.get(), PMONITOR, time);
} }
@@ -654,6 +684,9 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
if (!pSurface) if (!pSurface)
return; // wut? return; // wut?
if (g_pCompositor->m_bUnsafeState)
return;
pixman_region32_t damageBox; pixman_region32_t damageBox;
pixman_region32_init(&damageBox); pixman_region32_init(&damageBox);
wlr_surface_get_effective_damage(pSurface, &damageBox); wlr_surface_get_effective_damage(pSurface, &damageBox);
@@ -680,7 +713,7 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
wlr_region_scale(&damageBoxForEach, &damageBoxForEach, m->scale); wlr_region_scale(&damageBoxForEach, &damageBoxForEach, m->scale);
pixman_region32_translate(&damageBoxForEach, lx + m->vecPosition.x, ly + m->vecPosition.y); pixman_region32_translate(&damageBoxForEach, lx + m->vecPosition.x, ly + m->vecPosition.y);
wlr_output_damage_add(m->damage, &damageBoxForEach); m->addDamage(&damageBoxForEach);
} }
pixman_region32_fini(&damageBoxForEach); pixman_region32_fini(&damageBoxForEach);
@@ -694,11 +727,14 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
} }
void CHyprRenderer::damageWindow(CWindow* pWindow) { void CHyprRenderer::damageWindow(CWindow* pWindow) {
if (g_pCompositor->m_bUnsafeState)
return;
wlr_box damageBox = pWindow->getFullWindowBoundingBox(); wlr_box damageBox = pWindow->getFullWindowBoundingBox();
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
wlr_box fixedDamageBox = {damageBox.x - m->vecPosition.x, damageBox.y - m->vecPosition.y, damageBox.width, damageBox.height}; wlr_box fixedDamageBox = {damageBox.x - m->vecPosition.x, damageBox.y - m->vecPosition.y, damageBox.width, damageBox.height};
scaleBox(&fixedDamageBox, m->scale); scaleBox(&fixedDamageBox, m->scale);
wlr_output_damage_add_box(m->damage, &fixedDamageBox); m->addDamage(&fixedDamageBox);
} }
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
@@ -708,8 +744,11 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) {
} }
void CHyprRenderer::damageMonitor(CMonitor* pMonitor) { void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
if (g_pCompositor->m_bUnsafeState)
return;
wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y}; wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
wlr_output_damage_add_box(pMonitor->damage, &damageBox); pMonitor->addDamage(&damageBox);
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
@@ -718,10 +757,13 @@ void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
} }
void CHyprRenderer::damageBox(wlr_box* pBox) { void CHyprRenderer::damageBox(wlr_box* pBox) {
if (g_pCompositor->m_bUnsafeState)
return;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
wlr_box damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height}; wlr_box damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height};
scaleBox(&damageBox, m->scale); scaleBox(&damageBox, m->scale);
wlr_output_damage_add_box(m->damage, &damageBox); m->addDamage(&damageBox);
} }
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
@@ -778,7 +820,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
if (pMonitor->m_bEnabled) if (pMonitor->m_bEnabled)
pMonitor->onDisconnect(); pMonitor->onDisconnect();
return false; return true;
} }
if (!pMonitor->m_bEnabled) { if (!pMonitor->m_bEnabled) {
@@ -787,7 +829,14 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
// Check if the rule isn't already applied // 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()); Debug::log(LOG, "Not applying a new rule to %s because it's already applied!", pMonitor->szName.c_str());
return true; return true;
} }
@@ -859,6 +908,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} else { } else {
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000); wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
pMonitor->vecSize = pMonitorRule->resolution; pMonitor->vecSize = pMonitorRule->resolution;
Debug::log(LOG, "Setting custom mode for %s", pMonitor->output->name);
} }
} else { } else {
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
@@ -896,6 +947,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
Debug::log(LOG, "Setting preferred mode for %s", pMonitor->output->name);
} }
} }
@@ -918,9 +971,23 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor(); pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor();
pMonitor->vecTransformedSize = Vector2D(x,y); 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); wlr_output_enable(pMonitor->output, true);

View File

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

View File

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

View File

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

View File

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

View File

@@ -112,7 +112,7 @@ static void workspace_handle_remove(struct wl_client *client,
return; 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, static void workspace_handle_deactivate(struct wl_client *client,
@@ -312,7 +312,7 @@ void wlr_ext_workspace_handle_v1_destroy(
return; 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); 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; struct wlr_ext_workspace_group_handle_v1_create_workspace_event event;
event.workspace_group = group; event.workspace_group = group;
event.name = arg; 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, 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_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); workspace_manager_update_idle_source(group->manager);
struct wlr_ext_workspace_group_handle_v1_output *output, *tmp2; 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, 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 = struct wlr_ext_workspace_manager_v1 *manager =
wl_container_of(listener, manager, display_destroy); 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_list_remove(&manager->display_destroy.link);
wl_global_destroy(manager->global); wl_global_destroy(manager->global);