Compare commits

...

245 Commits

Author SHA1 Message Date
vaxerski
8a4e04d789 check window validity in getfirstwindowonworkspace 2022-08-01 00:45:06 +02:00
vaxerski
46e18e08d1 contain for the hyprland default bg 2022-07-31 23:44:04 +02:00
Kai
9ac00fe52b update flake.nix to version 0.9.0beta (#451) 2022-07-31 22:44:51 +03:00
vaxerski
d44adb1bea [gha] bump flake inputs 2022-07-31 18:31:50 +00:00
vaxerski
40c652f23e update wlroots dep 2022-07-31 20:30:43 +02:00
vaxerski
575c3e071a fix ls fadeout on scaled 2022-07-31 17:20:33 +02:00
vaxerski
dba4596c7e focus to first window on not found in refocus 2022-07-31 17:07:39 +02:00
vaxerski
e95aa8ef26 minor fixes to render loop 2022-07-31 16:54:36 +02:00
vaxerski
a1d1ec4c46 added misc:mouse_move_enables_dpms 2022-07-31 15:46:42 +02:00
Mihai Fufezan
d9687c93ee Nix: add cachix (#448) 2022-07-31 15:19:28 +03:00
vaxerski
9be239dac6 remove wlr_viewporter, we do not support it 2022-07-31 14:10:21 +02:00
vaxerski
76f7c2510e account for geom in initial XDG window popups 2022-07-31 14:05:47 +02:00
vaxerski
2230f0ccaa move to XDG 4 2022-07-31 13:21:33 +02:00
vaxerski
04f8029fcc fix minor XDG issue 2022-07-31 13:14:56 +02:00
vaxerski
20cba2d707 damage monitor on dpms on 2022-07-31 12:39:49 +02:00
vaxerski
e2bc07d276 fix lack of return in tickHyprctl 2022-07-31 12:35:10 +02:00
vaxerski
edac94bed1 tick hyprctl separately 2022-07-31 00:27:32 +02:00
Mihai Fufezan
4610b3d864 protocols: add wlr-output-power-management-unstable-v1.xml to meson.build 2022-07-31 01:09:26 +03:00
vaxerski
0573d5987f dont account for scale in border thick 2022-07-31 00:07:35 +02:00
vaxerski
e5cef8fc96 account for scale in downrounding 2022-07-31 00:04:34 +02:00
vaxerski
382f851b30 account for border in rounding 2022-07-31 00:00:24 +02:00
vaxerski
2e3d42a9a9 added a dpms dispatcher 2022-07-30 23:51:13 +02:00
vaxerski
217ff1f401 do not call dmabuf_create twice 2022-07-30 23:45:27 +02:00
vaxerski
c2db3ad8ce fix minor memory issue 2022-07-30 23:04:31 +02:00
vaxerski
2e0dd4bea2 use pref in default configs 2022-07-30 22:55:20 +02:00
vaxerski
d6a649c1b3 added preferred to monitor cfg 2022-07-30 22:54:29 +02:00
vaxerski
f96b611651 support wlr-output-power-management 2022-07-30 22:41:24 +02:00
vaxerski
4211b37e22 added misc:damage_entire_on_snapshot 2022-07-30 22:26:46 +02:00
vaxerski
45747fb8e6 fix snapshots on scaled 2022-07-30 22:22:51 +02:00
vaxerski
adeab98831 some window fadeout fixes 2022-07-30 22:07:40 +02:00
vaxerski
036be18bf5 fix shader fix 2022-07-30 19:00:38 +02:00
Mihai Fufezan
59879e0bd1 Nix module: make package nullable part 3 2022-07-30 18:19:27 +03:00
Mihai Fufezan
132b5ba5b6 Nix module: make package nullable part 2 2022-07-30 18:14:46 +03:00
Mihai Fufezan
3c544e1c31 Nix module: make package nullable 2022-07-30 18:11:46 +03:00
vaxerski
191c02a4f4 update decos on configureX11 2022-07-30 15:22:34 +02:00
vaxerski
7c7690eb08 windowrules for floating remove hidden flag 2022-07-30 12:42:27 +02:00
Mihai Fufezan
66680a1149 Nix: fix failing module 2022-07-29 18:39:10 +03:00
Vaxry
fd74208453 Merge pull request #446 from IanManske/movecurrentworkspace-nullmonitor-fix
Fix crash from moving current workspace to nonexistent (null) monitor.
2022-07-29 17:19:25 +02:00
vaxerski
e56699826f Optimize shaders 2022-07-29 17:07:33 +02:00
Ian Manske
ef2417fbcb Fix crash from moving current workspace to nonexistent (null) monitor. 2022-07-29 10:59:31 -04:00
reptee
fd999100f0 Remove extra packages in nix module (#343)
Co-authored-by: Mihai Fufezan <fufexan@pm.me>
Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
2022-07-29 14:35:38 +03:00
Mihai Fufezan
0eebf3ab16 meson: add -DGIT arguments (#321) 2022-07-29 13:21:19 +03:00
vaxerski
ac8e5fef10 even more damage scaled fixes 2022-07-29 11:52:56 +02:00
vaxerski
429a9bc6c3 hide only XWayland on incorrect size 2022-07-29 11:45:32 +02:00
vaxerski
233bad5011 Spam the protocols less with resizes of XDG 2022-07-28 23:55:00 +02:00
vaxerski
0f19bd99f8 more scaled surface damage fixes 2022-07-28 23:21:35 +02:00
vaxerski
f0cd784f79 fixes to surface damaging on scaled 3 2022-07-28 22:41:59 +02:00
vaxerski
7a2f296c93 surface damage fixes 2 2022-07-28 22:23:27 +02:00
vaxerski
0b0cd85085 surface damage fixes 2 2022-07-28 22:23:00 +02:00
vaxerski
3f62a386bf surface damage fixes 2022-07-28 22:15:56 +02:00
vaxerski
4076a3b6d7 fixed device configs 2022-07-28 21:38:30 +02:00
vaxerski
13d9c85e4e fix alpha with xwl opacity 2022-07-28 18:17:47 +02:00
vaxerski
9afa3953e9 fix crash oopsie 2022-07-28 17:56:11 +02:00
Vaxry
398662c75a Merge pull request #440 from Roger-Roger-debug/main
Fix hyprctl flags help
2022-07-28 17:47:56 +02:00
Roger Roger
5bc9534642 Fix hyprctl flags help 2022-07-28 16:42:18 +02:00
vaxerski
0e2038fedf minor fullscreen anim fixes 2022-07-28 16:33:45 +02:00
vaxerski
6d35d642ea fix fullscreen workspace slide anims 2022-07-28 15:56:55 +02:00
vaxerski
b0ab8afc58 fix some XWayland weird popups 2022-07-28 15:40:06 +02:00
vaxerski
578787b36d add gestures to example configs 2022-07-28 13:44:17 +02:00
vaxerski
f6c7a79988 update default configs for new anim config 2022-07-28 13:39:05 +02:00
vaxerski
9d5b76b757 fix typo in new anim handlers 2022-07-28 13:34:52 +02:00
vaxerski
920fdd6bff Animation config rework 2022-07-28 13:28:43 +02:00
vaxerski
9dd17a4be6 Added toggleopaque dispatcher 2022-07-28 12:07:41 +02:00
vaxerski
3904351678 Added layoutmsg and some master layout msgs 2022-07-28 12:00:10 +02:00
vaxerski
b6f2a4bc36 damage popups correctly 2022-07-28 11:37:27 +02:00
vaxerski
e102f9ec8c remove make man 2022-07-27 23:12:18 +02:00
vaxerski
ee15ad1215 render ls popups correctly 2022-07-27 18:02:20 +02:00
Gabriel Fontes
1d3e1472f2 nix: add home-manager module (#395) 2022-07-27 17:32:42 +03:00
Mihai Fufezan
b2627c05c4 flake & meson: 0.7.0 -> 0.8.1
nix: add legacyRenderer option
2022-07-27 14:57:59 +03:00
vaxerski
427bc35b6b fix empty workspace name on unspecified default 2022-07-27 13:56:01 +02:00
vaxerski
c9c4b14ef2 optimize xwayland has_alpha blur 2022-07-27 13:30:55 +02:00
vaxerski
cb1a36faf0 missed 2 structs 2022-07-27 12:36:56 +02:00
vaxerski
31a079b347 added DPMS 2022-07-27 12:32:00 +02:00
Vaxry
50b991674b Merge pull request #379 from volitank/main
docs: add man pages
2022-07-27 00:08:12 +02:00
vaxerski
28046e9da0 added binds:scroll_event_delay 2022-07-26 23:34:03 +02:00
vaxerski
cc146f0344 use transformed size in popup unconstrain 2022-07-26 22:58:25 +02:00
vaxerski
d3c1d3435c fix typo in XDG popup callbacks 2022-07-26 22:45:59 +02:00
vaxerski
57f5de68ae remove commit event cuz i forgot 2022-07-26 22:01:55 +02:00
vaxerski
eb30d9bdc8 fix typo in LS destroy event 2022-07-26 21:59:07 +02:00
vaxerski
98ef43496b listener fixes 2022-07-26 21:41:29 +02:00
vaxerski
1455442b9a fix swipe not cancelling constraints 2022-07-26 18:38:30 +02:00
vaxerski
71c1ff8ee3 log xwayland in hyprctl 2022-07-26 18:25:08 +02:00
vaxerski
b18a2738e3 schedule recalcs in LS 2022-07-26 18:22:34 +02:00
vaxerski
99ebbb36b2 README stuff 2022-07-26 17:34:53 +02:00
vaxerski
6f2368f809 Add a pass dispatcher 2022-07-26 17:30:30 +02:00
vaxerski
7dc014e967 r and e exclusivity in bind 2022-07-26 17:04:26 +02:00
vaxerski
66eac124e2 add binding to mouse buttons 2022-07-26 14:50:21 +02:00
vaxerski
d04f36c57d set moz env 2022-07-26 10:05:29 +02:00
vaxerski
7babcf7e6a arrange after switch 2022-07-25 23:53:43 +02:00
vaxerski
b0d91cbf3a simplify formats 2022-07-25 22:40:34 +02:00
vaxerski
db899e00e7 adjust ls fading out logic 2022-07-25 22:00:46 +02:00
vaxerski
6e16dfa5e5 use defines for unreachable 2022-07-25 21:34:57 +02:00
vaxerski
c998e946aa Wrap adding to fading out
needed to avoid memory safety issues, because sometimes there would be duplicates.
2022-07-25 21:08:54 +02:00
vaxerski
cde39e0b6e ls fixes 2022-07-25 20:47:56 +02:00
vaxerski
b1d3a1deea force unmap on direct destroy 2022-07-25 18:38:40 +02:00
vaxerski
e2594c79cc fix fading out layers without unmap 2022-07-25 18:35:53 +02:00
vaxerski
a0be6e19d8 fix shadowing with doesntHave 2022-07-25 16:12:06 +02:00
vaxerski
14176f01ca fix swiping with one workspace on monitor 2022-07-25 15:42:27 +02:00
Vaxry
574d950145 updated previews in readme 2022-07-25 15:05:23 +02:00
vaxerski
bb539f0a8d added keybind repeat flag 2022-07-25 14:42:49 +02:00
vaxerski
067e2d39f6 shadow with respect of keysym on press 2022-07-25 14:24:02 +02:00
vaxerski
e388a86c9d move floating windows manually on moveworkspacetomonitor 2022-07-25 14:22:32 +02:00
vaxerski
3e6abaf680 fix some swipe issues 2022-07-25 14:06:49 +02:00
vaxerski
6dc8c4b310 Shadowing Keybinds fixes 2022-07-24 14:35:58 +02:00
vaxerski
1ddd7ee713 remove forced envvars 2022-07-24 13:29:46 +02:00
vaxerski
92d1d21a3d added default touchpad settings to example configs 2022-07-24 12:23:31 +02:00
vaxerski
8dcc3032a8 fix keybinds shadowing multibinds 2022-07-24 12:16:26 +02:00
vaxerski
1626707b7f make layerSurfaces into RAII 2022-07-23 15:48:08 +02:00
Blake Lee
970bcc467c remove version 2022-07-22 15:32:56 -04:00
Mihai Fufezan
72700bf9dc layersurfaces: set default geometry 2022-07-22 20:28:43 +03:00
vaxerski
616ec22735 wrapped wl_listener fixes 2022-07-22 13:34:19 +02:00
vaxerski
d9b0edb786 remove newPopup handler for LS 2022-07-22 13:12:26 +02:00
vaxerski
3f169a937a fix wlr workspace names before init 2022-07-22 12:37:44 +02:00
vaxerski
fa1273f258 minor changes to swipes 2022-07-22 00:13:56 +02:00
vaxerski
8f66ddcad0 minor changes to swipes 2022-07-22 00:10:26 +02:00
vaxerski
4db1062af6 minor changes to swipes 2022-07-22 00:08:25 +02:00
vaxerski
0013ef9ef0 reload input after exec once 2022-07-21 20:30:48 +02:00
vaxerski
19cd04c85f shadow keybinds on drag events 2022-07-21 19:44:34 +02:00
Vaxry
a011c28227 Merge pull request #265 from xDarksome/main
Scroll workspaces with Super+MouseWheel
2022-07-21 19:40:15 +02:00
Darksome
d5ccca4fdb Consider scroll as a 'pressed' key 2022-07-21 20:31:38 +03:00
vaxerski
f512bf6b5a remove server from hyprctl as it's unused 2022-07-21 19:27:55 +02:00
Darksome
ce508f1cdc Fix merge 2022-07-21 19:48:34 +03:00
Darksome
eb8a1939e6 Merge upstream 2022-07-21 19:18:03 +03:00
Vaxry
7f660fed0d Merge pull request #404 from System-x64/new-hyprland.png
Updated assets/hyprland.png
2022-07-21 14:46:56 +02:00
vaxerski
75ce01b1a7 Make the thread manager into a wl event loop timer 2022-07-21 12:33:22 +02:00
Dikshant Namdeo
b9f8d900b3 updated-hyprland.png 2022-07-21 12:31:24 +05:30
vaxerski
189cbe9f09 added shadowing keybinds 2022-07-20 23:17:26 +02:00
vaxerski
fa2bd3b1a8 added keybinds on key up 2022-07-20 22:45:06 +02:00
vaxerski
fc33cae70c change bind flag parsing 2022-07-20 22:33:43 +02:00
vaxerski
641aaff998 minor code adjustments 2022-07-20 18:39:08 +02:00
vaxerski
9463e3eb0a fix transformed snapshots a bit 2022-07-20 16:28:05 +02:00
vaxerski
e6b151b6c3 fix memory read after free in damageSurface 2022-07-20 12:06:14 +02:00
vaxerski
d52446135b add sensitivity per device & reload mice on config 2022-07-19 19:26:53 +02:00
vaxerski
1ba600ca23 added workspace swipe fingers 2022-07-19 18:35:24 +02:00
vaxerski
0026414f9b fix workspace swipes mistake 2022-07-19 18:30:53 +02:00
vaxerski
ce8d655fad fix oopsie in log 2022-07-19 16:39:15 +02:00
vaxerski
d4690a5c5e minor change to unmanaged X11 geom requests 2022-07-19 16:38:27 +02:00
vaxerski
755245e752 adjust workspace on geom change x11 2022-07-19 16:21:35 +02:00
vaxerski
ec2afb563e fix oopsie include 2022-07-19 14:28:37 +02:00
vaxerski
59e34e311e fix oopsie include 2022-07-19 14:27:52 +02:00
vaxerski
c6c3d66373 fix hyprctl with relative negative 2022-07-19 14:24:03 +02:00
vaxerski
21217bcb2b notify enter on subsurfaces with follow mouse not 1 2022-07-19 14:05:12 +02:00
vaxerski
f905ae33c8 guard pSurface in unmapsubsurface 2022-07-19 13:54:42 +02:00
vaxerski
0281caa8e0 fix ASan error 2022-07-19 13:36:54 +02:00
Blake Lee
a312f8e0ac replace rst2man with pandoc 2022-07-18 18:56:46 -04:00
Vaxry
f35d513bf5 Merge pull request #391 from dgerblick/focuswindow-options
focuswindow options + other hyprctl bugs I found when testing
2022-07-18 23:19:12 +02:00
vaxerski
10a83853ac added ls noprocess 2022-07-18 21:16:01 +02:00
vaxerski
53b8263eb1 remove fixXwaylandwindowsonworkspace, not needed anymore 2022-07-18 21:15:46 +02:00
vaxerski
8bcfda2230 update moveactivetoworkspace logic 2022-07-18 20:53:29 +02:00
Daniel Gerblick
f2c0e6ef02 fixed issue causing hyprctl to output ill-formed json when strings include characters needing escaping 2022-07-18 14:47:28 -04:00
vaxerski
b669948737 fix logo center 2022-07-18 15:41:02 +02:00
vaxerski
a4b1d51c63 add new wallpapers 2022-07-18 15:31:59 +02:00
vaxerski
e7b8cda360 update logo 2022-07-18 15:23:26 +02:00
vaxerski
c466bd1219 fix webkit 2022-07-18 14:21:21 +02:00
vaxerski
ad19a15cef readme center 2022-07-18 14:20:43 +02:00
vaxerski
954a387cf9 fix center 2022-07-18 14:19:21 +02:00
vaxerski
a51f44d566 readme fix 2022-07-18 14:16:49 +02:00
vaxerski
423c9f9d56 new logo 2022-07-18 14:15:33 +02:00
vaxerski
900e6947e9 reject windows with tiny sizes, overwrite size 2022-07-18 13:14:31 +02:00
vaxerski
90d07d7b52 fix shadows on unmanaged and noborder 2022-07-18 12:39:57 +02:00
vaxerski
60cc33a53c added time logging 2022-07-18 11:46:42 +02:00
Daniel Gerblick
dc1f34c5fa added PID and address-based options for focuswindow, as well as updated hyprctl clients to be consistent with logs and hyprctl activewindow 2022-07-17 19:00:12 -04:00
vaxerski
afeb040684 fix selection events 2022-07-17 18:56:01 +02:00
vaxerski
f5bd30569f fix borders on scaled 2022-07-16 23:29:42 +02:00
vaxerski
6f1b9d6af9 add master:new_on_top 2022-07-16 23:24:42 +02:00
vaxerski
1848086abd reload layout on hyprctl layout 2022-07-16 22:44:29 +02:00
vaxerski
cb2989cec5 fix fade corner artifacts 2022-07-16 21:10:16 +02:00
vaxerski
16afa2c422 fix border rendering on certain windows
oversized subsurfaces had a tendency to be above borders, now they wont be
2022-07-16 20:57:59 +02:00
vaxerski
edcecae7a0 dont cycle on fullscreen 2022-07-16 19:55:40 +02:00
vaxerski
aac546b771 added center windowrule 2022-07-16 16:27:17 +02:00
vaxerski
ef24329495 pass through pinch events 2022-07-16 16:12:31 +02:00
vaxerski
5c836e6460 added master layout 2022-07-16 15:57:31 +02:00
Darksome
68cfc1a496 Merge branch 'main' of github.com:xDarksome/Hyprland 2022-07-16 15:35:47 +03:00
Darksome
08319dd1f5 Fix handleKeybinds debug log 2022-07-16 15:34:13 +03:00
xDarksome
4f9be67298 Merge branch 'hyprwm:main' into main 2022-07-16 15:30:32 +03:00
Darksome
ce9efb7ae3 Impl changeworkspace(e+{n}) 2022-07-16 15:28:17 +03:00
vaxerski
48e5bd96bc Added shadow colors animations and inactive col 2022-07-16 12:44:45 +02:00
Darksome
2ae088d631 Use correct wlroots commit 2022-07-16 12:47:37 +03:00
Darksome
fdbc54d97b Restore events/Devices.cpp formatting 2022-07-16 12:44:12 +03:00
Darksome
e56ff0fcb0 Merge remote-tracking branch 'upstream/main' into mouse-wheel-cfg 2022-07-16 12:40:02 +03:00
Darksome
43b7da0bb1 Rollback flake.lock 2022-07-16 12:30:07 +03:00
Blake Lee
88506d4284 Apply suggestions from code review 2022-07-15 22:34:35 -04:00
volitank
9fc74a708e Apply suggestions from code review
Co-authored-by: Mihai Fufezan <fufexan@pm.me>
2022-07-15 22:25:03 -04:00
Blake Lee
310a839700 docs: add man pages 2022-07-15 20:04:17 -04:00
vaxerski
b2650928ea obey xdg reqs better 2022-07-16 00:11:21 +02:00
Vaxry
069e3b2114 Merge pull request #376 from dgerblick/hyprctl-json-segfault-fix
Fixed SEGFAULT when running hyprctl with only the -j option
2022-07-15 23:21:46 +02:00
Daniel Gerblick
db693ec7e5 Fixed SEGFAULT when running hyprctl with only the -j option 2022-07-15 15:39:39 -04:00
xDarksome
16fecac2d1 [gha] bump flake inputs 2022-07-15 18:55:08 +00:00
Darksome
1eceae811f Try mouse wheel configuration 2022-07-15 21:54:05 +03:00
vaxerski
fbcc6936f4 fix dashes in hyprctl 2022-07-15 20:07:52 +02:00
vaxerski
90ebeaa881 fixed fullscreen opacity on fullscreen 1 2022-07-15 19:33:09 +02:00
vaxerski
1441856811 fix blur on oversized, default to enabled 2022-07-15 19:21:13 +02:00
vaxerski
19c646ab47 Minor changes to the renderer's overflow behavior
Won't squish base layers anymore
2022-07-15 19:07:06 +02:00
Darksome
5388b54442 Merge upstream 2022-07-15 19:42:03 +03:00
vaxerski
6306d4dae3 add remove, to blurls 2022-07-15 13:29:56 +02:00
Vaxry
5af26a451a Merge pull request #373 from fufexan/configpath
Add config flag
2022-07-15 12:03:50 +02:00
vaxerski
ba48e7ceea fixed up hyprctl flags 2022-07-15 11:58:09 +02:00
vaxerski
c0377457df don't poison wlr in make install 2022-07-15 11:39:11 +02:00
Mihai Fufezan
202fb4d8d4 add clangd cache in gitignore 2022-07-15 00:10:00 +03:00
Mihai Fufezan
d8fee02063 add simple help message 2022-07-15 00:09:31 +03:00
Mihai Fufezan
01fc3d6068 add config flag
you can now specify a config with -c <path>
2022-07-14 23:55:24 +03:00
vaxerski
634970a284 update deco values on fullscreen 2022-07-14 22:49:49 +02:00
vaxerski
642af5395e dont focus anything on constrained 2022-07-14 21:33:36 +02:00
Vaxry
316589406f Merge pull request #372 from bazuin-32/main
Fix error when running `hyprctl dispatch exec` with an arg that contains a `/`
2022-07-14 19:33:21 +02:00
bazuin-32
0085319c18 Fix error when running hyprctl dispatch exec with an arg that contains
a `/`
2022-07-14 11:23:18 -06:00
vaxerski
0488f17976 fix opacity inactive methodology 2022-07-14 18:46:42 +02:00
vaxerski
8b52858bb5 fix opacity active 2022-07-14 18:45:16 +02:00
Vaxry
b0dd370421 Merge pull request #342 from viperML/main
ci: add release workflow
2022-07-14 12:54:49 +02:00
vaxerski
65e75c0b44 fix backwards hyprctl compat 2022-07-14 11:43:15 +02:00
Vaxry
7c999fb9f5 Merge pull request #242 from calebowens/caleb-feature-add-width-multiplier
Added a multiplier for the width to height ratio
2022-07-14 11:38:49 +02:00
Kainoa Kanter
21da348826 hyprwm in readme links 2022-07-13 11:23:43 -07:00
vaxerski
c2215e4efb fix focus on fullscreen and over 2022-07-13 18:33:36 +02:00
vaxerski
49dbb586e3 fixed session-less envs 2022-07-13 18:31:09 +02:00
Vaxry
6708f3b133 Fixed TTY switching (#364) 2022-07-13 18:18:23 +02:00
vaxerski
ef7ee2fd0f added active keymap prop 2022-07-13 16:02:14 +02:00
vaxerski
e93b45615c better doc in help 2022-07-13 15:50:46 +02:00
vaxerski
0a16513946 fix warning 2022-07-13 15:48:47 +02:00
vaxerski
99e9503732 flag pos 2022-07-13 15:47:35 +02:00
Vaxry
be69098cb8 Merge pull request #360 from bazuin-32/main
Add hyprctl output in json when `-j` flag is used
2022-07-13 15:44:59 +02:00
Fernando Ayats
d7d5b1a4eb ci: fix repo source 2022-07-13 10:39:57 +02:00
Fernando Ayats
868fc6e0f3 Revert "FIXME: temp disable workflows"
This reverts commit 532ffe1681.
2022-07-13 10:36:47 +02:00
Fernando Ayats
9580ef4bc2 ci: upload source 2022-07-13 10:35:23 +02:00
Fernando Ayats
532ffe1681 FIXME: temp disable workflows 2022-07-13 10:26:11 +02:00
Fernando Ayats
0cfc97972f ci: upload source 2022-07-13 10:25:21 +02:00
bazuin-32
ab859ec9fc Fix issues with batch requests 2022-07-12 16:34:28 -06:00
bazuin-32
ac9ff795cd Fix calls to substr with invalid pos 2022-07-12 15:38:50 -06:00
vaxerski
4bea3467e0 update hyprctl help 2022-07-12 23:21:00 +02:00
vaxerski
bca93f4d3c code styling 2022-07-12 23:17:55 +02:00
vaxerski
bf762f566f Fix VRAM memory leak when releasing snapshots 2022-07-12 23:11:34 +02:00
bazuin-32
2402f2e364 Use enum for specifying hyprctl output format and change the way flags
are passed for json output
2022-07-12 14:59:36 -06:00
bazuin-32
036f431206 Add hyprctl output in json when -j flag is used 2022-07-12 11:57:33 -06:00
Mihai Fufezan
f9985a36b3 nix & meson: 0.6.2 -> 0.7.0 2022-07-12 20:12:59 +03:00
vaxerski
ad03360665 fix device sections shadowing parse errors 2022-07-12 16:07:51 +02:00
vaxerski
3914672dd5 mention more config options in cfgs 2022-07-12 15:41:42 +02:00
vaxerski
78c6371743 default vfr to off 2022-07-12 15:41:28 +02:00
Vaxry
f789a14527 updated issue guidelines 2022-07-12 15:35:23 +02:00
Darksome
cb8a6f881b Disallow scrolling into empty workspaces 2022-07-02 19:55:35 +03:00
xDarksome
185c4d6ea1 Merge branch 'hyprwm:main' into main 2022-07-02 19:43:52 +03:00
xDarksome
fc4b10d13c Remove empty line 2022-06-26 19:28:30 +03:00
xDarksome
504f76112a Merge branch 'hyprwm:main' into main 2022-06-26 19:20:20 +03:00
xDarksome
be460ea954 Merge branch 'hyprwm:main' into main 2022-06-24 18:58:11 +03:00
Darksome
776ca3baf2 Change workspace wheel scrolling direction 2022-06-24 18:57:14 +03:00
Darksome
8f62f6d4b0 Add workspace switching with mouse wheel 2022-06-20 22:47:28 +03:00
Caleb Owens
7d80327e7d fixed vertical swapping issue 2022-06-20 17:11:59 +01:00
Caleb Owens
3d46c73981 Added a multiplier for the width to height ratio 2022-06-20 14:37:27 +01:00
90 changed files with 3820 additions and 1002 deletions

View File

@@ -13,9 +13,13 @@ jobs:
- name: Install nix
uses: cachix/install-nix-action@v17
with:
install_url: https://releases.nixos.org/nix/nix-2.8.0/install
install_url: https://releases.nixos.org/nix/nix-2.10.3/install
extra_nix_config: |
auto-optimise-store = true
experimental-features = nix-command flakes
- name: Build HyprLand with default settings
- uses: cachix/cachix-action@v10
with:
name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Build Hyprland with default settings
run: nix build --print-build-logs

38
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Release artifacts
on:
release:
types: [published]
workflow_dispatch:
jobs:
source-tarball:
runs-on: ubuntu-latest
steps:
- name: Checkout Hyprland
id: checkout
uses: actions/checkout@v3
with:
submodules: recursive
- name: Create tarball with submodules
id: tar
run: tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
- id: whatrelease
name: Get latest release
uses: pozetroninc/github-action-get-latest-release@master
with:
owner: hyprwm
repo: Hyprland
excludes: prerelease, draft
- name: Upload to release
id: upload
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: source.tar.gz
asset_name: source-${{ steps.whatrelease.outputs.release }}.tar.gz
tag: ${{ steps.whatrelease.outputs.release }}
overwrite: true

1
.gitignore vendored
View File

@@ -13,6 +13,7 @@ build/
result
/.vscode/
.envrc
.cache
*.o
*-protocol.c

View File

@@ -9,6 +9,8 @@ PKGS = wlroots wayland-server xcb xkbcommon libinput
CFLAGS += $(foreach p,$(PKGS),$(shell pkg-config --cflags $(p)))
LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p)))
DATE=$(shell date "+%d %b %Y")
xdg-shell-protocol.h:
$(WAYLAND_SCANNER) server-header \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
@@ -79,6 +81,16 @@ idle-protocol.c:
idle-protocol.o: idle-protocol.h
wlr-output-power-management-unstable-v1-protocol.h:
$(WAYLAND_SCANNER) server-header \
protocols/wlr-output-power-management-unstable-v1.xml $@
wlr-output-power-management-unstable-v1-protocol.c:
$(WAYLAND_SCANNER) private-code \
protocols/wlr-output-power-management-unstable-v1.xml $@
wlr-output-power-management-unstable-v1-protocol.o: wlr-output-power-management-unstable-v1-protocol.h
legacyrenderer:
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:STRING=true -H./ -B./build -G Ninja
cmake --build ./build --config Release --target all -j 10
@@ -107,11 +119,13 @@ all:
cd ./hyprctl && make all && cd ..
install:
[ ! -d /usr/include/wlr ] || mv /usr/include/wlr /usr/include/wlrBackup
[ ! -f /usr/lib/libwlroots.so ] || mv /usr/lib/libwlroots.so /usr/lib/libwlroots.so.backup
[ ! -f /usr/lib/pkgconfig/wlroots.pc ] || mv /usr/lib/pkgconfig/wlroots.pc /usr/lib/pkgconfig/wlroots.pc.backup
make clear
make fixwlr
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../..
make protocols
make release
cd hyprctl && make all && cd ..
make all
mkdir -p ${PREFIX}/share/wayland-sessions
cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions/
mkdir -p ${PREFIX}/bin
@@ -122,13 +136,6 @@ install:
cp ./assets/wall_4K.png ${PREFIX}/share/hyprland
cp ./assets/wall_8K.png ${PREFIX}/share/hyprland
rm -rf /usr/include/wlr
rm -f /usr/lib/libwlroots.so
rm -f /usr/lib/pkgconfig/wlroots.pc
[ ! -d /usr/include/wlrBackup ] || mv /usr/include/wlrBackup /usr/include/wlr
[ ! -f /usr/lib/libwlroots.so.backup ] || mv -f /usr/lib/libwlroots.so.backup /usr/lib/libwlroots.so
[ ! -f /usr/lib/pkgconfig/wlroots.pc.backup ] || mv -f /usr/lib/pkgconfig/wlroots.pc.backup /usr/lib/pkgconfig/wlroots.pc
uninstall:
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
rm -f ${PREFIX}/bin/Hyprland
@@ -136,7 +143,7 @@ uninstall:
rm -f /usr/lib/libwlroots.so.11032
rm -rf ${PREFIX}/share/hyprland
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
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
fixwlr:
sed -i -E 's/(soversion = 11)([^032]|$$)/soversion = 11032/g' subprojects/wlroots/meson.build
@@ -152,3 +159,20 @@ config:
cd subprojects/wlroots && ninja -C build/
cd subprojects/wlroots && ninja -C build/ install
man:
pandoc ./docs/Hyprland.1.rst \
--standalone \
--variable=header:"Hyprland User Manual" \
--variable=date:"${DATE}" \
--variable=section:1 \
--from rst \
--to man | gzip -c > /usr/share/man/man1/Hyprland.1.gz
pandoc ./docs/hyprctl.1.rst \
--standalone \
--variable=header:"hyprctl User Manual" \
--variable=date:"${DATE}" \
--variable=section:1 \
--from rst \
--to man | gzip -c > /usr/share/man/man1/hyprctl.1.gz

View File

@@ -1,6 +1,6 @@
<div align = center>
<img src="https://raw.githubusercontent.com/vaxerski/Hyprland/main/assets/header.svg" width="1000" height="500" alt="banner">
<img src="https://raw.githubusercontent.com/vaxerski/Hyprland/main/assets/header.svg" width="750" height="300" alt="banner">
<br>
@@ -57,6 +57,7 @@ Try it out and report bugs / suggestions!
- Drop shadows
- Fully dynamic workspaces
- Closely follows `wlroots-git`
- Global keybinds passed to your apps of choice
- Bundled wlroots
- Window/layer fade in/out
- Tiling/pseudotiling/floating/fullscreen windows
@@ -69,6 +70,7 @@ Try it out and report bugs / suggestions!
- Full damage tracking
- Docks support
- Drawing tablet support
- and much more...
<br>
<br>
@@ -122,18 +124,18 @@ Try it out and report bugs / suggestions!
<!----------------------------------------------------------------------------->
[Configure]: https://github.com/vaxerski/Hyprland/wiki/Configuring-Hyprland
[Configure]: https://github.com/hyprwm/Hyprland/wiki/Configuring-Hyprland
[Discord]: https://discord.gg/hQ9XvMUjjr
[Stars]: https://starchart.cc/vaxerski/Hyprland
[Hypr]: https://github.com/vaxerski/Hypr
[Stars]: https://starchart.cc/hyprwm/Hyprland
[Hypr]: https://github.com/hyprwm/Hypr
[Pull Requests]: https://github.com/vaxerski/Hyprland/pulls
[Issues]: https://github.com/vaxerski/Hyprland/issues
[Todo]: https://github.com/vaxerski/Hyprland/projects?type=beta
[Pull Requests]: https://github.com/hyprwm/Hyprland/pulls
[Issues]: https://github.com/hyprwm/Hyprland/issues
[Todo]: https://github.com/hyprwm/Hyprland/projects?type=beta
[Contribute]: https://github.com/vaxerski/Hyprland/wiki/Contributing-&-Debugging
[Install]: https://github.com/vaxerski/Hyprland/wiki/Installation
[Quick Start]: https://github.com/vaxerski/Hyprland/wiki/Quick-start
[Contribute]: https://github.com/hyprwm/Hyprland/wiki/Contributing-&-Debugging
[Install]: https://github.com/hyprwm/Hyprland/wiki/Installation
[Quick Start]: https://github.com/hyprwm/Hyprland/wiki/Quick-start
[License]: LICENSE
@@ -149,19 +151,19 @@ Try it out and report bugs / suggestions!
<!----------------------------------{ Images }--------------------------------->
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
[Preview A]: https://i.imgur.com/NbrTnZH.png
[Preview B]: https://i.imgur.com/ZA4Fa8R.png
[Preview C]: https://i.imgur.com/BpXxM8H.png
[Preview A]: https://i.imgur.com/sCafdKQ.png
[Preview B]: https://i.imgur.com/NbrTnZH.png
[Preview C]: https://i.imgur.com/ZA4Fa8R.png
<!----------------------------------{ Badges }--------------------------------->
[Badge Workflow]: https://github.com/vaxerski/Hyprland/actions/workflows/ci.yaml/badge.svg
[Badge Workflow]: https://github.com/hyprwm/Hyprland/actions/workflows/ci.yaml/badge.svg
[Badge Discord]: https://img.shields.io/badge/Join%20the-Discord%20server-6666ff
[Badge Issues]: https://img.shields.io/github/issues/vaxerski/Hyprland
[Badge Pull Requests]: https://img.shields.io/github/issues-pr/vaxerski/Hyprland
[Badge Language]: https://img.shields.io/github/languages/top/vaxerski/Hyprland
[Badge License]: https://img.shields.io/github/license/vaxerski/Hyprland
[Badge Lines]: https://img.shields.io/tokei/lines/github/vaxerski/Hyprland
[Badge Issues]: https://img.shields.io/github/issues/hyprwm/Hyprland
[Badge Pull Requests]: https://img.shields.io/github/issues-pr/hyprwm/Hyprland
[Badge Language]: https://img.shields.io/github/languages/top/hyprwm/Hyprland
[Badge License]: https://img.shields.io/github/license/hyprwm/Hyprland
[Badge Lines]: https://img.shields.io/tokei/lines/github/hyprwm/Hyprland
[Badge Hi Mom]: https://img.shields.io/badge/Hi-mom!-ff69b4

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 798 KiB

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

After

Width:  |  Height:  |  Size: 146 KiB

58
docs/Hyprland.1.rst Normal file
View File

@@ -0,0 +1,58 @@
:title: Hyprland
:author: Vaxerski <*https://github.com/vaxerski*>
NAME
====
Hyprland - Dynamic tiling Wayland compositor
SYNOPSIS
========
**Hyprland** [*arg [...]*].
DESCRIPTION
===========
**Hyprland** is a dynamic tiling Wayland compositor based on
wlroots that doesn't sacrifice on its looks.
You can launch Hyprland by either going into a TTY and
executing **Hyprland**, or with a login manager.
NOTICE
======
Hyprland is still in pretty early development compared to some other Wayland compositors.
Although Hyprland is pretty stable, it may have some bugs.
CONFIGURATION
=============
For configuration information please see <*https://github.com/hyprwm/Hyprland/wiki*>.
OPTIONS
=======
**-h**, **--help**
Show command usage.
**-c**, **--config**
Specify config file to use.
BUGS
====
Submit bug reports and request features online at:
<*https://github.com/hyprwm/Hyprland/issues*>
SEE ALSO
========
Sources at: <*https://github.com/hyprwm/Hyprland*>
COPYRIGHT
=========
Copyright (c) 2022, vaxerski

View File

@@ -26,6 +26,7 @@ If your bug is one that doesn't crash Hyprland, but feels like invalid behavior,
If your bug crashes Hyprland, append additionally:
- The Hyprland log
- Coredump / Coredump analysis (with a stacktrace)
- Your config
**Important**: Please do NOT use any package for reporting bugs! Clone and compile from source.

121
docs/hyprctl.1.rst Normal file
View File

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

View File

@@ -3,7 +3,12 @@
#
# Refer to the wiki for more information.
monitor=,1280x720@60,0x0,1
#
# Please note not all available settings / options are set here.
# For a full list, see the wiki (basic and advanced configuring)
#
monitor=,preferred,0x0,1
workspace=DP-1,1
input {
@@ -14,6 +19,10 @@ input {
kb_rules=
follow_mouse=1
touchpad {
natural_scroll=no
}
}
general {
@@ -44,8 +53,8 @@ decoration {
animations {
enabled=1
animation=windows,1,7,default
animation=borders,1,10,default
animation=fadein,1,10,default
animation=border,1,10,default
animation=fade,1,10,default
animation=workspaces,1,6,default
}
@@ -53,6 +62,10 @@ dwindle {
pseudotile=0 # enable pseudotiling on dwindle
}
gestures {
workspace_swipe=no
}
# example window rules
# for windows named/classed as abc and xyz
#windowrule=move 69 420,abc
@@ -97,3 +110,6 @@ bind=ALT,7,movetoworkspace,7
bind=ALT,8,movetoworkspace,8
bind=ALT,9,movetoworkspace,9
bind=ALT,0,movetoworkspace,10
bind=SUPER,mouse_down,workspace,e+1
bind=SUPER,mouse_up,workspace,e-1

12
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1657447684,
"narHash": "sha256-FCP9AuU1q6PE3vOeM5SFf58f/UKPBAsoSGDUGamNBbo=",
"lastModified": 1659219666,
"narHash": "sha256-pzYr5fokQPHv7CmUXioOhhzDy/XyWOIXP4LZvv/T7Mk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5f43d8b088d3771274bcfb69d3c7435b1121ac88",
"rev": "7b9be38c7250b22d829ab6effdee90d5e40c6e5c",
"type": "github"
},
"original": {
@@ -26,11 +26,11 @@
"flake": false,
"locked": {
"host": "gitlab.freedesktop.org",
"lastModified": 1656865312,
"narHash": "sha256-xtQ0zwJZwN8sciruveM10CzKz6TWxBY8SyXa8E4jly4=",
"lastModified": 1658770113,
"narHash": "sha256-VBq9vw0hvQPKGKLNKLJS8xsUHvrX0o2LUDBVolixenE=",
"owner": "wlroots",
"repo": "wlroots",
"rev": "5dc1d4671dd2ca3c1f0f09587c463fdbb542f0a4",
"rev": "7b5e890e61a27375725068a7d1884b26851b3102",
"type": "gitlab"
},
"original": {

View File

@@ -33,7 +33,7 @@
});
hyprland = prev.callPackage ./nix/default.nix {
stdenv = prev.gcc12Stdenv;
version = "0.6.2beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101"));
version = "0.9.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101"));
wlroots = wlroots-hyprland;
};
hyprland-debug = hyprland.override {debug = true;};
@@ -61,6 +61,7 @@
formatter = genSystems (system: pkgsFor.${system}.alejandra);
nixosModules.default = import ./nix/module.nix self;
homeManagerModules.default = import ./nix/hm-module.nix self;
overlay = throw "Hyprland: .overlay output is deprecated, please use the .overlays.default output";
};

View File

@@ -1,4 +1,4 @@
all:
g++ -std=c++20 ./main.cpp -o ./hyprctl
g++ -std=c++23 ./main.cpp -o ./hyprctl
clean:
rm ./hyprctl
rm ./hyprctl

View File

@@ -9,14 +9,18 @@
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <ranges>
#include <algorithm>
#include <iostream>
#include <string>
#include <fstream>
#include <string>
#include <deque>
const std::string USAGE = R"#(usage: hyprctl [command] [(opt)args]
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
commands:
monitors
workspaces
clients
@@ -29,7 +33,12 @@ const std::string USAGE = R"#(usage: hyprctl [command] [(opt)args]
kill
splash
hyprpaper
reload)#";
reload
flags:
-j -> output in JSON
--batch -> execute a batch of commands, separated by ';'
)#";
void request(std::string arg) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -97,13 +106,6 @@ void requestHyprpaper(std::string arg) {
return;
}
const auto SERVER = gethostbyname("localhost");
if (!SERVER) {
std::cout << "Couldn't get host (2)";
return;
}
// get the instance signature
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
@@ -154,7 +156,7 @@ void dispatchRequest(int argc, char** argv) {
return;
}
std::string rq = "dispatch " + std::string(argv[2]) + " " + std::string(argv[3]);
std::string rq = "/dispatch " + std::string(argv[2]) + " " + std::string(argv[3]);
request(rq);
}
@@ -181,12 +183,25 @@ void hyprpaperRequest(int argc, char** argv) {
requestHyprpaper(rq);
}
void batchRequest(int argc, char** argv) {
std::string rq = "[[BATCH]]" + std::string(argv[2]);
void batchRequest(std::string arg) {
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
request(rq);
}
std::deque<std::string> splitArgs(int argc, char** argv) {
std::deque<std::string> result;
for (auto i = 1 /* skip the executable */; i < argc; ++i)
result.push_back(std::string(argv[i]));
return result;
}
bool isNumber(const std::string& str, bool allowfloat) {
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
}
int main(int argc, char** argv) {
int bflag = 0, sflag = 0, index, c;
@@ -195,21 +210,52 @@ int main(int argc, char** argv) {
return 1;
}
if (!strcmp(argv[1], "monitors")) request("monitors");
else if (!strcmp(argv[1], "clients")) request("clients");
else if (!strcmp(argv[1], "workspaces")) request("workspaces");
else if (!strcmp(argv[1], "activewindow")) request("activewindow");
else if (!strcmp(argv[1], "layers")) request("layers");
else if (!strcmp(argv[1], "version")) request("version");
else if (!strcmp(argv[1], "kill")) request("kill");
else if (!strcmp(argv[1], "splash")) request("splash");
else if (!strcmp(argv[1], "devices")) request("devices");
else if (!strcmp(argv[1], "reload")) request("reload");
else if (!strcmp(argv[1], "dispatch")) dispatchRequest(argc, argv);
else if (!strcmp(argv[1], "keyword")) keywordRequest(argc, argv);
else if (!strcmp(argv[1], "hyprpaper")) hyprpaperRequest(argc, argv);
else if (!strcmp(argv[1], "--batch")) batchRequest(argc, argv);
else if (!strcmp(argv[1], "--help")) printf("%s", USAGE.c_str());
std::string fullRequest = "";
std::string fullArgs = "";
const auto ARGS = splitArgs(argc, argv);
for (auto i = 0; i < ARGS.size(); ++i) {
if (ARGS[i][0] == '-' && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
// parse
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
fullArgs += "j";
} else if (ARGS[i] == "--batch") {
fullRequest = "--batch ";
} else {
printf("%s\n", USAGE.c_str());
return 1;
}
continue;
}
fullRequest += ARGS[i] + " ";
}
if (fullRequest.empty()) {
printf("%s\n", USAGE.c_str());
return 1;
}
fullRequest.pop_back(); // remove trailing space
fullRequest = fullArgs + "/" + fullRequest;
if (fullRequest.contains("/--batch")) batchRequest(fullRequest);
else if (fullRequest.contains("/monitors")) request(fullRequest);
else if (fullRequest.contains("/clients")) request(fullRequest);
else if (fullRequest.contains("/workspaces")) request(fullRequest);
else if (fullRequest.contains("/activewindow")) request(fullRequest);
else if (fullRequest.contains("/layers")) request(fullRequest);
else if (fullRequest.contains("/version")) request(fullRequest);
else if (fullRequest.contains("/kill")) request(fullRequest);
else if (fullRequest.contains("/splash")) request(fullRequest);
else if (fullRequest.contains("/devices")) request(fullRequest);
else if (fullRequest.contains("/reload")) request(fullRequest);
else if (fullRequest.contains("/dispatch")) dispatchRequest(argc, argv);
else if (fullRequest.contains("/keyword")) keywordRequest(argc, argv);
else if (fullRequest.contains("/hyprpaper")) hyprpaperRequest(argc, argv);
else if (fullRequest.contains("/--help")) printf("%s", USAGE.c_str());
else {
printf("%s\n", USAGE.c_str());
return 1;

View File

@@ -1,15 +1,25 @@
project('Hyprland', 'cpp', 'c',
version : '0.6.2beta',
version : '0.8.1beta',
default_options : ['warning_level=2', 'default_library=static', 'optimization=3'])
add_global_arguments('-std=c++23', language: 'cpp')
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_MESSAGE = run_command('bash', '-c', 'git show | head -n 5 | tail -n 1', check: false).stdout().strip()
GIT_DIRTY = run_command('bash', '-c', 'git diff-index --quiet HEAD -- || echo "dirty"', check: false).stdout().strip()
add_project_arguments(
[
'-Wno-unused-parameter',
'-Wno-unused-value',
'-Wno-missing-field-initializers',
'-Wno-narrowing',
f'-DGIT_BRANCH="@GIT_BRANCH@"',
f'-DGIT_COMMIT_HASH="@GIT_COMMIT_HASH@"',
f'-DGIT_COMMIT_MESSAGE="@GIT_COMMIT_MESSAGE@"',
f'-DGIT_DIRTY="@GIT_DIRTY@"',
],
language: 'cpp')

View File

@@ -5,6 +5,7 @@
pkg-config,
meson,
ninja,
git,
libdrm,
libinput,
libxcb,
@@ -18,9 +19,10 @@
wlroots,
xcbutilwm,
xwayland,
enableXWayland ? true,
version ? "git",
debug ? false,
enableXWayland ? true,
legacyRenderer ? false,
version ? "git",
}:
stdenv.mkDerivation {
pname = "hyprland" + lib.optionalString debug "-debug";
@@ -35,6 +37,7 @@ stdenv.mkDerivation {
buildInputs =
[
git
libdrm
libinput
libxcb
@@ -54,7 +57,10 @@ stdenv.mkDerivation {
then "debug"
else "release";
mesonFlags = lib.optional (!enableXWayland) "-DNO_XWAYLAND=true";
mesonFlags = builtins.concatLists [
(lib.optional (!enableXWayland) "-DNO_XWAYLAND=true")
(lib.optional (legacyRenderer) "-DLEGACY_RENDERER:STRING=true")
];
patches = [
# make meson use the provided wlroots instead of the git submodule

98
nix/hm-module.nix Normal file
View File

@@ -0,0 +1,98 @@
self: {
config,
lib,
pkgs,
...
}: let
cfg = config.wayland.windowManager.hyprland;
defaultHyprlandPackage = self.packages.${pkgs.system}.default.override {
enableXWayland = cfg.xwayland;
};
in {
options.wayland.windowManager.hyprland = {
enable = lib.mkEnableOption "hyprland wayland compositor";
package = lib.mkOption {
type = with lib.types; nullOr package;
default = defaultHyprlandPackage;
description = ''
Hyprland package to use. Will override the 'xwayland' option.
Defaults to the one provided by the flake. Set it to
<literal>pkgs.hyprland</literal> to use the one provided by nixpkgs or
if you have an overlay.
Set to null to not add any Hyprland package to your path. This should
be done if you want to use the NixOS module to install Hyprland.
'';
};
systemdIntegration = lib.mkOption {
type = lib.types.bool;
default = pkgs.stdenv.isLinux;
description = ''
Whether to enable <filename>hyprland-session.target</filename> on
hyprland startup. This links to <filename>graphical-session.target</filename>.
Some important environment variables will be imported to systemd
and dbus user environment before reaching the target, including
<itemizedlist>
<listitem><para><literal>DISPLAY</literal></para></listitem>
<listitem><para><literal>WAYLAND_DISPLAY</literal></para></listitem>
<listitem><para><literal>HYPRLAND_INSTANCE_SIGNATURE</literal></para></listitem>
<listitem><para><literal>XDG_CURRENT_DESKTOP</literal></para></listitem>
</itemizedlist>
'';
};
xwayland = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Enable xwayland.
'';
};
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
Extra configuration lines to add to ~/.config/hypr/hyprland.conf.
'';
};
};
config = lib.mkIf cfg.enable {
home.packages =
lib.optional (cfg.package != null) cfg.package
++ lib.optional cfg.xwayland pkgs.xwayland;
xdg.configFile."hypr/hyprland.conf" = {
text =
(lib.optionalString cfg.systemdIntegration "
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP; systemctl --user start hyprland-session.target
")
+ cfg.extraConfig;
onChange = let
hyprlandPackage =
if cfg.package == null
then defaultHyprlandPackage
else cfg.package;
in "${hyprlandPackage}/bin/hyprctl reload";
};
systemd.user.targets.hyprland-session = lib.mkIf cfg.systemdIntegration {
Unit = {
Description = "hyprland compositor session";
Documentation = ["man:systemd.special(7)"];
BindsTo = ["graphical-session.target"];
Wants = ["graphical-session-pre.target"];
After = ["graphical-session-pre.target"];
};
};
systemd.user.targets.tray = {
Unit = {
Description = "Home Manager System Tray";
Requires = ["graphical-session-pre.target"];
};
};
};
}

View File

@@ -18,7 +18,7 @@ in {
'';
package = mkOption {
type = types.package;
type = types.nullOr types.package;
default = self.packages.${pkgs.system}.default;
defaultText = literalExpression "<Hyprland flake>.packages.<system>.default";
example = literalExpression "<Hyprland flake>.packages.<system>.default.override { }";
@@ -27,34 +27,18 @@ in {
'';
};
extraPackages = mkOption {
type = with types; listOf package;
default = with pkgs; [
kitty
wofi
swaybg
];
defaultText = literalExpression ''
with pkgs; [ kitty wofi swaybg ];
'';
example = literalExpression ''
with pkgs; [
alacritty wofi
]
'';
description = ''
Extra packages to be installed system wide.
'';
};
imports = [
(mkRemovedOptionModule ["programs" "hyprland" "extraPackages"] "extraPackages has been removed. Use environment.systemPackages instead.")
];
};
config = mkIf cfg.enable {
environment.systemPackages = [cfg.package] ++ cfg.extraPackages;
environment.systemPackages = lib.optional (cfg.package != null) cfg.package;
security.polkit.enable = true;
hardware.opengl.enable = mkDefault true;
fonts.enableDefaultFonts = mkDefault true;
programs.dconf.enable = mkDefault true;
services.xserver.displayManager.sessionPackages = [cfg.package];
services.xserver.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package;
programs.xwayland.enable = mkDefault true;
xdg.portal.enable = mkDefault true;
xdg.portal.extraPortals = [pkgs.xdg-desktop-portal-wlr];

View File

@@ -14,6 +14,7 @@ wayland_scanner = find_program(
protocols = [
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['wlr-output-power-management-unstable-v1.xml'],
['ext-workspace-unstable-v1.xml'],
['pointer-constraints-unstable-v1.xml'],
['tablet-unstable-v2.xml'],

View File

@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_output_power_management_unstable_v1">
<copyright>
Copyright © 2019 Purism SPC
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>
<description summary="Control power management modes of outputs">
This protocol allows clients to control power management modes
of outputs that are currently part of the compositor space. The
intent is to allow special clients like desktop shells to power
down outputs when the system is idle.
To modify outputs not currently part of the compositor space see
wlr-output-management.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible changes
may be added together with the corresponding interface version bump.
Backward incompatible changes are done by bumping the version number in
the protocol and interface names and resetting the interface version.
Once the protocol is to be declared stable, the 'z' prefix and the
version number in the protocol and interface names are removed and the
interface version number is reset.
</description>
<interface name="zwlr_output_power_manager_v1" version="1">
<description summary="manager to create per-output power management">
This interface is a manager that allows creating per-output power
management mode controls.
</description>
<request name="get_output_power">
<description summary="get a power management for an output">
Create a output power management mode control that can be used to
adjust the power management mode for a given output.
</description>
<arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
<arg name="output" type="object" interface="wl_output"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the manager">
All objects created by the manager will still remain valid, until their
appropriate destroy request has been called.
</description>
</request>
</interface>
<interface name="zwlr_output_power_v1" version="1">
<description summary="adjust power management mode for an output">
This object offers requests to set the power management mode of
an output.
</description>
<enum name="mode">
<entry name="off" value="0"
summary="Output is turned off."/>
<entry name="on" value="1"
summary="Output is turned on, no power saving"/>
</enum>
<enum name="error">
<entry name="invalid_mode" value="1" summary="inexistent power save mode"/>
</enum>
<request name="set_mode">
<description summary="Set an outputs power save mode">
Set an output's power save mode to the given mode. The mode change
is effective immediately. If the output does not support the given
mode a failed event is sent.
</description>
<arg name="mode" type="uint" enum="mode" summary="the power save mode to set"/>
</request>
<event name="mode">
<description summary="Report a power management mode change">
Report the power management mode change of an output.
The mode event is sent after an output changed its power
management mode. The reason can be a client using set_mode or the
compositor deciding to change an output's mode.
This event is also sent immediately when the object is created
so the client is informed about the current power management mode.
</description>
<arg name="mode" type="uint" enum="mode"
summary="the output's new power management mode"/>
</event>
<event name="failed">
<description summary="object no longer valid">
This event indicates that the output power management mode control
is no longer valid. This can happen for a number of reasons,
including:
- The output doesn't support power management
- Another client already has exclusive power management mode control
for this output
- The output disappeared
Upon receiving this event, the client should destroy this object.
</description>
</event>
<request name="destroy" type="destructor">
<description summary="destroy this power management">
Destroys the output power management mode control object.
</description>
</request>
</interface>
</protocol>

View File

@@ -1,8 +1,21 @@
#include "Compositor.hpp"
#include "helpers/Splashes.hpp"
#include <random>
#include "debug/HyprCtl.hpp"
int handleCritSignal(int signo, void* data) {
Debug::log(LOG, "Hyprland received signal %d", signo);
if (signo == SIGTERM || signo == SIGINT || signo == SIGKILL) {
g_pCompositor->cleanup();
}
return 0; // everything went fine
}
CCompositor::CCompositor() {
wlr_log_init(WLR_INFO, NULL);
m_szInstanceSignature = GIT_COMMIT_HASH + std::string("_") + std::to_string(time(NULL));
setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true);
@@ -30,6 +43,12 @@ CCompositor::CCompositor() {
m_sWLDisplay = wl_display_create();
m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay);
// register crit signal handler
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
//wl_event_loop_add_signal(m_sWLEventLoop, SIGINT, handleCritSignal, nullptr);
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay);
if (!m_sWLRBackend) {
@@ -70,20 +89,21 @@ CCompositor::CCompositor() {
m_sWLRSubCompositor = wlr_subcompositor_create(m_sWLDisplay);
m_sWLRDataDevMgr = wlr_data_device_manager_create(m_sWLDisplay);
m_sWLRDmabuf = wlr_linux_dmabuf_v1_create(m_sWLDisplay, m_sWLRRenderer);
wlr_export_dmabuf_manager_v1_create(m_sWLDisplay);
wlr_screencopy_manager_v1_create(m_sWLDisplay);
wlr_data_control_manager_v1_create(m_sWLDisplay);
wlr_gamma_control_manager_v1_create(m_sWLDisplay);
wlr_primary_selection_v1_device_manager_create(m_sWLDisplay);
wlr_viewporter_create(m_sWLDisplay);
// wlr_viewporter_create(m_sWLDisplay); // TODO: support wl_viewporter
m_sWLROutputLayout = wlr_output_layout_create();
m_sWLROutputPowerMgr = wlr_output_power_manager_v1_create(m_sWLDisplay);
m_sWLRScene = wlr_scene_create();
wlr_scene_attach_output_layout(m_sWLRScene, m_sWLROutputLayout);
m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 3);
m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 4);
m_sWLRCursor = wlr_cursor_create();
wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout);
@@ -131,15 +151,12 @@ CCompositor::CCompositor() {
wlr_xdg_foreign_v2_create(m_sWLDisplay, m_sWLRForeignRegistry);
m_sWLRPointerGestures = wlr_pointer_gestures_v1_create(m_sWLDisplay);
m_sWLRSession = wlr_backend_get_session(m_sWLRBackend);
}
CCompositor::~CCompositor() {
cleanupExit();
}
void handleCritSignal(int signo) {
g_pCompositor->cleanupExit();
exit(signo);
cleanup();
}
void CCompositor::setRandomSplash() {
@@ -161,11 +178,16 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRCursor->events.swipe_begin, &Events::listen_swipeBegin, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.swipe_update, &Events::listen_swipeUpdate, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.swipe_end, &Events::listen_swipeEnd, 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_end, &Events::listen_pinchEnd, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend");
addWLSignal(&m_sSeat.seat->events.request_set_cursor, &Events::listen_requestMouse, &m_sSeat, "Seat");
addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat");
addWLSignal(&m_sSeat.seat->events.request_start_drag, &Events::listen_requestDrag, &m_sSeat, "Seat");
addWLSignal(&m_sSeat.seat->events.start_drag, &Events::listen_startDrag, &m_sSeat, "Seat");
addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat");
addWLSignal(&m_sSeat.seat->events.request_set_primary_selection, &Events::listen_requestSetPrimarySel, &m_sSeat, "Seat");
addWLSignal(&m_sWLRLayerShell->events.new_surface, &Events::listen_newLayerSurface, m_sWLRLayerShell, "LayerShell");
addWLSignal(&m_sWLROutputLayout->events.change, &Events::listen_change, m_sWLROutputLayout, "OutputLayout");
addWLSignal(&m_sWLROutputMgr->events.apply, &Events::listen_outputMgrApply, m_sWLROutputMgr, "OutputMgr");
@@ -177,12 +199,12 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr");
addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer");
addWLSignal(&m_sWLRIdleInhibitMgr->events.new_inhibitor, &Events::listen_newIdleInhibitor, m_sWLRIdleInhibitMgr, "WLRIdleInhibitMgr");
signal(SIGINT, handleCritSignal);
signal(SIGTERM, handleCritSignal);
addWLSignal(&m_sWLROutputPowerMgr->events.set_mode, &Events::listen_powerMgrSetMode, m_sWLROutputPowerMgr, "PowerMgr");
if (m_sWLRSession)
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
}
void CCompositor::cleanupExit() {
void CCompositor::cleanup() {
if (!m_sWLDisplay)
return;
@@ -197,8 +219,7 @@ void CCompositor::cleanupExit() {
g_pXWaylandManager->m_sWLRXWayland = nullptr;
}
wl_display_destroy_clients(m_sWLDisplay);
wl_display_destroy(m_sWLDisplay);
wl_display_terminate(m_sWLDisplay);
m_sWLDisplay = nullptr;
}
@@ -216,6 +237,9 @@ void CCompositor::startCompositor() {
Debug::log(LOG, "Creating the AnimationManager!");
g_pAnimationManager = std::make_unique<CAnimationManager>();
Debug::log(LOG, "Creating the LayoutManager!");
g_pLayoutManager = std::make_unique<CLayoutManager>();
Debug::log(LOG, "Creating the ConfigManager!");
g_pConfigManager = std::make_unique<CConfigManager>();
@@ -234,9 +258,6 @@ void CCompositor::startCompositor() {
Debug::log(LOG, "Creating the XWaylandManager!");
g_pXWaylandManager = std::make_unique<CHyprXWaylandManager>();
Debug::log(LOG, "Creating the LayoutManager!");
g_pLayoutManager = std::make_unique<CLayoutManager>();
Debug::log(LOG, "Creating the EventManager!");
g_pEventManager = std::make_unique<CEventManager>();
g_pEventManager->startThread();
@@ -246,17 +267,11 @@ void CCompositor::startCompositor() {
//
//
// firefox wont detect wl
setenv("MOZ_ENABLE_WAYLAND", "1", 1);
initAllSignals();
// Set some env vars so that Firefox is automatically in Wayland mode
// and QT apps too
// electron needs -- flags so we can't really set them here
setenv("QT_QPA_PLATFORM", "wayland", true);
setenv("MOZ_ENABLE_WAYLAND", "1", true);
// Set XDG_CURRENT_DESKTOP to our compositor's name
setenv("XDG_CURRENT_DESKTOP", "hyprland", true);
m_szWLDisplaySocket = wl_display_add_socket_auto(m_sWLDisplay);
if (!m_szWLDisplaySocket) {
@@ -285,7 +300,7 @@ void CCompositor::startCompositor() {
wl_display_run(m_sWLDisplay);
}
SMonitor* CCompositor::getMonitorFromID(const int& id) {
CMonitor* CCompositor::getMonitorFromID(const int& id) {
for (auto& m : m_vMonitors) {
if (m->ID == (uint64_t)id) {
return m.get();
@@ -295,7 +310,7 @@ SMonitor* CCompositor::getMonitorFromID(const int& id) {
return nullptr;
}
SMonitor* CCompositor::getMonitorFromName(const std::string& name) {
CMonitor* CCompositor::getMonitorFromName(const std::string& name) {
for (auto& m : m_vMonitors) {
if (m->szName == name) {
return m.get();
@@ -305,18 +320,18 @@ SMonitor* CCompositor::getMonitorFromName(const std::string& name) {
return nullptr;
}
SMonitor* CCompositor::getMonitorFromCursor() {
CMonitor* CCompositor::getMonitorFromCursor() {
const auto COORDS = Vector2D(m_sWLRCursor->x, m_sWLRCursor->y);
return getMonitorFromVector(COORDS);
}
SMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
const auto OUTPUT = wlr_output_layout_output_at(m_sWLROutputLayout, point.x, point.y);
if (!OUTPUT) {
float bestDistance = 0.f;
SMonitor* pBestMon = nullptr;
CMonitor* pBestMon = nullptr;
for (auto& m : m_vMonitors) {
float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize);
@@ -569,7 +584,7 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
return PSURFACE->surface;
}
SMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
for (auto& m : m_vMonitors) {
if (m->output == out) {
return m.get();
@@ -630,7 +645,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
updateWindowAnimatedDecorationValues(pWindow);
// Send an event
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)
wlr_foreign_toplevel_handle_v1_set_activated(pWindow->m_phForeignToplevel, true);
@@ -647,7 +662,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
if (!pSurface) {
wlr_seat_keyboard_clear_focus(m_sSeat.seat);
g_pEventManager->postEvent(SHyprIPCEvent("activewindow", ",")); // unfocused
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused
return;
}
@@ -700,7 +715,7 @@ CWindow* CCompositor::getWindowForPopup(wlr_xdg_popup* popup) {
return nullptr;
}
wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::list<SLayerSurface*>* layerSurfaces, Vector2D* sCoords, SLayerSurface** ppLayerSurfaceFound) {
wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<std::unique_ptr<SLayerSurface>>* layerSurfaces, Vector2D* sCoords, SLayerSurface** ppLayerSurfaceFound) {
for (auto it = layerSurfaces->rbegin(); it != layerSurfaces->rend(); it++) {
if ((*it)->fadingOut || !(*it)->layerSurface || ((*it)->layerSurface && !(*it)->layerSurface->mapped))
continue;
@@ -708,7 +723,7 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::list<SL
const auto SURFACEAT = wlr_layer_surface_v1_surface_at((*it)->layerSurface, pos.x - (*it)->geometry.x, pos.y - (*it)->geometry.y, &sCoords->x, &sCoords->y);
if (SURFACEAT) {
*ppLayerSurfaceFound = *it;
*ppLayerSurfaceFound = it->get();
return SURFACEAT;
}
}
@@ -795,7 +810,7 @@ int CCompositor::getWindowsOnWorkspace(const int& id) {
CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) {
for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == id)
if (w->m_iWorkspaceID == id && w->m_bIsMapped && !w->m_bHidden)
return w.get();
}
@@ -803,6 +818,9 @@ CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) {
}
void CCompositor::fixXWaylandWindowsOnWorkspace(const int& id) {
// not needed anymore
return;
const auto ISVISIBLE = isWorkspaceVisible(id);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
@@ -852,9 +870,12 @@ void CCompositor::moveWindowToTop(CWindow* pWindow) {
}
}
void CCompositor::cleanupFadingOut() {
void CCompositor::cleanupFadingOut(const int& monid) {
for (auto& w : m_vWindowsFadingOut) {
if (w->m_iMonitorID != (long unsigned int)monid)
continue;
bool valid = windowExists(w);
if (!valid || !w->m_bFadingOut || w->m_fAlpha.fl() == 0.f) {
@@ -867,31 +888,84 @@ void CCompositor::cleanupFadingOut() {
m_vWindowsFadingOut.erase(std::remove(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), w));
Debug::log(LOG, "Cleanup: destroyed a window");
glFlush(); // to free mem NOW.
return;
}
}
for (auto& ls : m_vSurfacesFadingOut) {
// sometimes somehow fucking happens wtf
bool exists = false;
for (auto& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLists) {
for (auto& lsp : lsl) {
if (lsp.get() == ls) {
exists = true;
break;
}
}
if (exists)
break;
}
if (exists)
break;
}
if (!exists) {
m_vSurfacesFadingOut.erase(std::remove(m_vSurfacesFadingOut.begin(), m_vSurfacesFadingOut.end(), ls));
Debug::log(LOG, "Fading out a non-existent LS??");
return;
}
if (ls->monitorID != monid)
continue;
if (ls->fadingOut && ls->readyToDelete && !ls->alpha.isBeingAnimated()) {
g_pHyprOpenGL->m_mLayerFramebuffers[ls].release();
g_pHyprOpenGL->m_mLayerFramebuffers.erase(ls);
for (auto& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLists) {
lsl.remove(ls);
if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](std::unique_ptr<SLayerSurface>& other) { return other.get() == ls; }) != lsl.end()) {
lsl.erase(std::remove_if(lsl.begin(), lsl.end(), [&](std::unique_ptr<SLayerSurface>& other) { return other.get() == ls; }));
}
}
}
g_pHyprOpenGL->m_mLayerFramebuffers[ls].release();
g_pHyprOpenGL->m_mLayerFramebuffers.erase(ls);
delete ls;
m_vSurfacesFadingOut.erase(std::remove(m_vSurfacesFadingOut.begin(), m_vSurfacesFadingOut.end(), ls));
Debug::log(LOG, "Cleanup: destroyed a layersurface");
glFlush(); // to free mem NOW.
return;
}
}
}
void CCompositor::addToFadingOutSafe(SLayerSurface* pLS) {
const auto FOUND = std::find_if(m_vSurfacesFadingOut.begin(), m_vSurfacesFadingOut.end(), [&](SLayerSurface* other) { return other == pLS; });
if (FOUND != m_vSurfacesFadingOut.end())
return; // if it's already added, don't add it.
m_vSurfacesFadingOut.emplace_back(pLS);
}
void CCompositor::addToFadingOutSafe(CWindow* pWindow) {
const auto FOUND = std::find_if(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), [&](CWindow* other) { return other == pWindow; });
if (FOUND != m_vWindowsFadingOut.end())
return; // if it's already added, don't add it.
m_vWindowsFadingOut.emplace_back(pWindow);
}
CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
const auto WINDOWIDEALBB = pWindow->getWindowIdealBoundingBoxIgnoreReserved();
@@ -1073,12 +1147,12 @@ CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) {
return nullptr;
}
SMonitor* CCompositor::getMonitorInDirection(const char& dir) {
CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
const auto POSA = m_pLastMonitor->vecPosition;
const auto SIZEA = m_pLastMonitor->vecSize;
auto longestIntersect = -1;
SMonitor* longestIntersectMonitor = nullptr;
CMonitor* longestIntersectMonitor = nullptr;
for (auto& m : m_vMonitors) {
if (m.get() == m_pLastMonitor)
@@ -1150,7 +1224,8 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
static auto *const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
static auto *const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
static auto *const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue;
static auto *const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue;
static auto *const PSHADOWCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive")->intValue;
// border
const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow);
@@ -1168,15 +1243,26 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
pWindow->m_fActiveInactiveAlpha = *PFULLSCREENALPHA;
else {
if (pWindow == m_pLastWindow)
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alpha != -1 ? pWindow->m_sSpecialRenderData.alpha : *PACTIVEALPHA;
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alpha * *PACTIVEALPHA;
else
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? pWindow->m_sSpecialRenderData.alphaInactive : *PINACTIVEALPHA;
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? pWindow->m_sSpecialRenderData.alphaInactive * *PINACTIVEALPHA : *PINACTIVEALPHA;
}
} else {
if (pWindow == m_pLastWindow)
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alpha != -1 ? pWindow->m_sSpecialRenderData.alpha : *PACTIVEALPHA;
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alpha * *PACTIVEALPHA;
else
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? pWindow->m_sSpecialRenderData.alphaInactive : *PINACTIVEALPHA;
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? pWindow->m_sSpecialRenderData.alphaInactive * *PINACTIVEALPHA : *PINACTIVEALPHA;
}
// shadow
if (pWindow->m_iX11Type != 2 && !pWindow->m_bX11DoesntWantBorders) {
if (pWindow == m_pLastWindow) {
pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL);
} else {
pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
}
} else {
pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow
}
}
@@ -1197,7 +1283,7 @@ int CCompositor::getNextAvailableMonitorID() {
return topID + 1;
}
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, SMonitor* pMonitor) {
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor) {
// We trust the workspace and monitor to be correct.
@@ -1239,8 +1325,14 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, SMonitor* pMoni
pWorkspace->moveToMonitor(pMonitor->ID);
for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == pWorkspace->m_iID)
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
w->m_iMonitorID = pMonitor->ID;
// additionally, move floating windows manually
if (w->m_bIsFloating && w->m_bIsMapped && !w->m_bHidden) {
w->m_vRealPosition = w->m_vRealPosition.vec() - POLDMON->vecPosition + pMonitor->vecPosition;
}
}
}
if (SWITCHINGISACTIVE) { // if it was active, preserve its' status. If it wasn't, don't.
@@ -1325,3 +1417,84 @@ void CCompositor::updateWorkspaceWindowDecos(const int& id) {
w->updateWindowDecos();
}
}
void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
return;
wlr_output_schedule_frame(pMonitor->output);
}
CWindow* CCompositor::getWindowByRegex(const std::string& regexp) {
eFocusWindowMode mode = MODE_CLASS_REGEX;
std::regex regexCheck(regexp);
std::string matchCheck;
if (regexp.find("title:") == 0) {
mode = MODE_TITLE_REGEX;
regexCheck = std::regex(regexp.substr(6));
} else if (regexp.find("address:") == 0) {
mode = MODE_ADDRESS;
matchCheck = regexp.substr(8);
} else if (regexp.find("pid:") == 0) {
mode = MODE_PID;
matchCheck = regexp.substr(4);
}
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_bHidden)
continue;
switch (mode) {
case MODE_CLASS_REGEX: {
const auto windowClass = g_pXWaylandManager->getAppIDClass(w.get());
if (!std::regex_search(g_pXWaylandManager->getAppIDClass(w.get()), regexCheck))
continue;
break;
}
case MODE_TITLE_REGEX: {
const auto windowTitle = g_pXWaylandManager->getTitle(w.get());
if (!std::regex_search(windowTitle, regexCheck))
continue;
break;
}
case MODE_ADDRESS: {
std::string addr = getFormat("0x%x", w.get());
if (matchCheck != addr)
continue;
break;
}
case MODE_PID: {
std::string pid = getFormat("%d", w->getPID());
if (matchCheck != pid)
continue;
break;
}
default:
break;
}
return w.get();
}
return nullptr;
}
wl_event_source* hyprCtlTickSource = nullptr;
int hyprCtlTick(void* data) {
HyprCtl::tickHyprCtl(); // so that we dont get that race condition multithread bullshit
wl_event_source_timer_update(hyprCtlTickSource, 16); // tick it 60/s, should be enough.
return 0;
}
void CCompositor::startHyprCtlTick() {
if (hyprCtlTickSource)
return;
hyprCtlTickSource = wl_event_loop_add_timer(m_sWLEventLoop, hyprCtlTick, nullptr);
wl_event_source_timer_update(hyprCtlTickSource, 16);
}

View File

@@ -30,7 +30,9 @@ public:
// ------------------ WLR BASICS ------------------ //
wl_display* m_sWLDisplay;
wl_event_loop* m_sWLEventLoop;
wlr_backend* m_sWLRBackend;
wlr_session* m_sWLRSession;
wlr_renderer* m_sWLRRenderer;
wlr_allocator* m_sWLRAllocator;
wlr_compositor* m_sWLRCompositor;
@@ -63,6 +65,7 @@ public:
wlr_xdg_foreign_registry* m_sWLRForeignRegistry;
wlr_idle_inhibit_manager_v1* m_sWLRIdleInhibitMgr;
wlr_pointer_gestures_v1* m_sWLRPointerGestures;
wlr_output_power_manager_v1* m_sWLROutputPowerMgr;
// ------------------------------------------------- //
@@ -70,7 +73,8 @@ public:
std::string m_szInstanceSignature = "";
std::string m_szCurrentSplash = "error";
std::vector<std::unique_ptr<SMonitor>> m_vMonitors;
std::vector<std::shared_ptr<CMonitor>> m_vMonitors;
std::vector<std::shared_ptr<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
std::vector<std::unique_ptr<CWindow>> m_vWindows;
std::deque<std::unique_ptr<CWindow>> m_dUnmanagedX11Windows;
std::vector<std::unique_ptr<SXDGPopup>> m_vXDGPopups;
@@ -80,22 +84,24 @@ public:
std::vector<SLayerSurface*> m_vSurfacesFadingOut;
void startCompositor();
void cleanupExit();
void cleanup();
wlr_surface* m_pLastFocus = nullptr;
CWindow* m_pLastWindow = nullptr;
SMonitor* m_pLastMonitor = nullptr;
CMonitor* m_pLastMonitor = nullptr;
SSeat m_sSeat;
bool m_bReadyToProcess = false;
bool m_bSessionActive = true;
bool m_bDPMSStateON = true;
// ------------------------------------------------- //
SMonitor* getMonitorFromID(const int&);
SMonitor* getMonitorFromName(const std::string&);
SMonitor* getMonitorFromCursor();
SMonitor* getMonitorFromVector(const Vector2D&);
CMonitor* getMonitorFromID(const int&);
CMonitor* getMonitorFromName(const std::string&);
CMonitor* getMonitorFromCursor();
CMonitor* getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(CWindow*);
void focusWindow(CWindow*, wlr_surface* pSurface = nullptr);
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
@@ -104,11 +110,11 @@ public:
CWindow* vectorToWindow(const Vector2D&);
CWindow* vectorToWindowIdeal(const Vector2D&); // used only for finding a window to focus on, basically a "findFocusableWindow"
CWindow* vectorToWindowTiled(const Vector2D&);
wlr_surface* vectorToLayerSurface(const Vector2D&, std::list<SLayerSurface*>*, Vector2D*, SLayerSurface**);
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
CWindow* windowFromCursor();
CWindow* windowFloatingFromCursor();
SMonitor* getMonitorFromOutput(wlr_output*);
CMonitor* getMonitorFromOutput(wlr_output*);
CWindow* getWindowForPopup(wlr_xdg_popup*);
CWindow* getWindowFromSurface(wlr_surface*);
bool isWorkspaceVisible(const int&);
@@ -124,7 +130,7 @@ public:
bool doesSeatAcceptInput(wlr_surface*);
bool isWindowActive(CWindow*);
void moveWindowToTop(CWindow*);
void cleanupFadingOut();
void cleanupFadingOut(const int& monid);
CWindow* getWindowInDirection(CWindow*, char);
void deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclude = nullptr);
CWindow* getNextWindowOnWorkspace(CWindow*);
@@ -132,20 +138,28 @@ public:
int getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&);
CWindow* getConstraintWindow(SMouse*);
SMonitor* getMonitorInDirection(const char&);
CMonitor* getMonitorInDirection(const char&);
void updateAllWindowsAnimatedDecorationValues();
void updateWindowAnimatedDecorationValues(CWindow*);
void moveWindowToWorkspace(CWindow*, const std::string&);
int getNextAvailableMonitorID();
void moveWorkspaceToMonitor(CWorkspace*, SMonitor*);
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
bool workspaceIDOutOfBounds(const int&);
void setWindowFullscreen(CWindow*, bool, eFullscreenMode);
void moveUnmanagedX11ToWindows(CWindow*);
CWindow* getX11Parent(CWindow*);
void scheduleFrameForMonitor(CMonitor*);
void addToFadingOutSafe(SLayerSurface*);
void addToFadingOutSafe(CWindow*);
CWindow* getWindowByRegex(const std::string&);
std::string explicitConfigPath;
void startHyprCtlTick();
private:
void initAllSignals();
void setRandomSplash();
void setRandomSplash();
};

View File

@@ -3,11 +3,12 @@
#include "render/decorations/CHyprDropShadowDecoration.hpp"
CWindow::CWindow() {
m_vRealPosition.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*) this, AVARDAMAGE_ENTIRE);
m_vRealSize.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE);
m_cRealBorderColor.create(AVARTYPE_COLOR, &g_pConfigManager->getConfigValuePtr("animations:borders_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:borders")->intValue, &g_pConfigManager->getConfigValuePtr("animations:borders_curve")->strValue, (void*)this, AVARDAMAGE_BORDER);
m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE);
m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE);
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*) this, AVARDAMAGE_ENTIRE);
m_vRealSize.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_cRealBorderColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE);
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
m_dWindowDecorations.emplace_back(std::make_unique<CHyprDropShadowDecoration>(this)); // put the shadow so it's the first deco (has to be rendered first)
}
@@ -103,3 +104,12 @@ pid_t CWindow::getPID() {
return PID;
}
IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) {
for (auto& wd : m_dWindowDecorations) {
if (wd->getDecorationType() == type)
return wd.get();
}
return nullptr;
}

View File

@@ -16,6 +16,7 @@ struct SWindowAdditionalConfigData {
std::string animationStyle = "";
int rounding = -1; // -1 means no
bool forceNoBlur = false;
bool forceOpaque = false;
};
class CWindow {
@@ -31,6 +32,10 @@ public:
DYNLISTENER(setGeometryX11U);
DYNLISTENER(fullscreenWindow);
DYNLISTENER(newPopupXDG);
DYNLISTENER(requestMove);
DYNLISTENER(requestMinimize);
DYNLISTENER(requestMaximize);
DYNLISTENER(requestResize);
// DYNLISTENER(newSubsurfaceWindow);
union {
@@ -46,6 +51,10 @@ public:
CAnimatedVariable m_vRealPosition;
CAnimatedVariable m_vRealSize;
// for not spamming the protocols
Vector2D m_vReportedPosition;
Vector2D m_vReportedSize;
// this is used for pseudotiling
bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(0,0);
@@ -109,6 +118,9 @@ public:
// for alpha
CAnimatedVariable m_fActiveInactiveAlpha;
// animated shadow color
CAnimatedVariable m_cRealShadowColor;
// For the list lookup
bool operator==(const CWindow& rhs) {
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut;
@@ -119,5 +131,6 @@ public:
wlr_box getWindowIdealBoundingBoxIgnoreReserved();
void updateWindowDecos();
pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType);
};

View File

@@ -12,11 +12,20 @@
CConfigManager::CConfigManager() {
setDefaultVars();
static const char* const ENVHOME = getenv("HOME");
const std::string CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf");
setDefaultAnimationVars();
std::string CONFIGPATH;
if (g_pCompositor->explicitConfigPath == "") {
static const char* const ENVHOME = getenv("HOME");
CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf");
} else {
CONFIGPATH = g_pCompositor->explicitConfigPath;
}
configPaths.emplace_back(CONFIGPATH);
Debug::disableLogs = &configValues["debug:disable_logs"].intValue;
Debug::disableTime = &configValues["debug:disable_time"].intValue;
}
void CConfigManager::setDefaultVars() {
@@ -36,16 +45,21 @@ void CConfigManager::setDefaultVars() {
configValues["general:col.active_border"].intValue = 0xffffffff;
configValues["general:col.inactive_border"].intValue = 0xff444444;
configValues["general:cursor_inactive_timeout"].intValue = 0;
configValues["general:layout"].strValue = "dwindle";
configValues["misc:disable_hyprland_logo"].intValue = 0;
configValues["misc:disable_splash_rendering"].intValue = 0;
configValues["misc:no_vfr"].intValue = 0;
configValues["misc:no_vfr"].intValue = 1;
configValues["misc:damage_entire_on_snapshot"].intValue = 0;
configValues["misc:mouse_move_enables_dpms"].intValue = 0;
configValues["debug:int"].intValue = 0;
configValues["debug:log_damage"].intValue = 0;
configValues["debug:overlay"].intValue = 0;
configValues["debug:damage_blink"].intValue = 0;
configValues["debug:disable_logs"].intValue = 0;
configValues["debug:disable_time"].intValue = 1;
configValues["decoration:rounding"].intValue = 1;
configValues["decoration:blur"].intValue = 1;
@@ -56,13 +70,14 @@ void CConfigManager::setDefaultVars() {
configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 1;
configValues["decoration:multisample_edges"].intValue = 1;
configValues["decoration:no_blur_on_oversized"].intValue = 1;
configValues["decoration:no_blur_on_oversized"].intValue = 0;
configValues["decoration:drop_shadow"].intValue = 1;
configValues["decoration:shadow_range"].intValue = 4;
configValues["decoration:shadow_render_power"].intValue = 3;
configValues["decoration:shadow_ignore_window"].intValue = 1;
configValues["decoration:shadow_offset"].strValue = "0 0";
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:col.group_border"].intValue = 0x66777700;
@@ -70,6 +85,11 @@ void CConfigManager::setDefaultVars() {
configValues["dwindle:force_split"].intValue = 0;
configValues["dwindle:preserve_split"].intValue = 0;
configValues["dwindle:special_scale_factor"].floatValue = 0.8f;
configValues["dwindle:split_width_multiplier"].floatValue = 1.0f;
configValues["master:special_scale_factor"].floatValue = 0.8f;
configValues["master:new_is_master"].intValue = 1;
configValues["master:new_on_top"].intValue = 0;
configValues["animations:enabled"].intValue = 1;
configValues["animations:speed"].floatValue = 7.f;
@@ -91,6 +111,7 @@ void CConfigManager::setDefaultVars() {
configValues["animations:workspaces_speed"].floatValue = 0.f;
configValues["animations:workspaces"].intValue = 1;
configValues["input:sensitivity"].floatValue = 0.f;
configValues["input:kb_layout"].strValue = "us";
configValues["input:kb_variant"].strValue = STRVAL_EMPTY;
configValues["input:kb_options"].strValue = STRVAL_EMPTY;
@@ -108,7 +129,11 @@ void CConfigManager::setDefaultVars() {
configValues["input:touchpad:tap-to-click"].intValue = 1;
configValues["input:touchpad:drag_lock"].intValue = 0;
configValues["binds:pass_mouse_when_bound"].intValue = 1;
configValues["binds:scroll_event_delay"].intValue = 300;
configValues["gestures:workspace_swipe"].intValue = 0;
configValues["gestures:workspace_swipe_fingers"].intValue = 3;
configValues["gestures:workspace_swipe_distance"].intValue = 300;
configValues["gestures:workspace_swipe_invert"].intValue = 1;
configValues["gestures:workspace_swipe_min_speed_to_force"].intValue = 30;
@@ -122,6 +147,7 @@ void CConfigManager::setDefaultVars() {
void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
auto& cfgValues = deviceConfigs[dev];
cfgValues["sensitivity"].floatValue = 0.f;
cfgValues["kb_layout"].strValue = "us";
cfgValues["kb_variant"].strValue = STRVAL_EMPTY;
cfgValues["kb_options"].strValue = STRVAL_EMPTY;
@@ -138,6 +164,56 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
cfgValues["drag_lock"].intValue = 0;
}
void CConfigManager::setDefaultAnimationVars() {
if (isFirstLaunch) {
INITANIMCFG("global");
INITANIMCFG("windows");
INITANIMCFG("fade");
INITANIMCFG("border");
INITANIMCFG("workspaces");
// windows
INITANIMCFG("windowsIn");
INITANIMCFG("windowsOut");
INITANIMCFG("windowsMove");
// fade
INITANIMCFG("fadeIn");
INITANIMCFG("fadeOut");
INITANIMCFG("fadeSwitch");
INITANIMCFG("fadeShadow");
// border
// workspaces
}
// init the values
animationConfig["global"] = {
false,
"default",
"",
8.f,
1,
&animationConfig["general"],
nullptr
};
CREATEANIMCFG("windows", "global");
CREATEANIMCFG("fade", "global");
CREATEANIMCFG("border", "global");
CREATEANIMCFG("workspaces", "global");
CREATEANIMCFG("windowsIn", "windows");
CREATEANIMCFG("windowsOut", "windows");
CREATEANIMCFG("windowsMove", "windows");
CREATEANIMCFG("fadeIn", "fade");
CREATEANIMCFG("fadeOut", "fade");
CREATEANIMCFG("fadeSwitch", "fade");
CREATEANIMCFG("fadeShadow", "fade");
}
void CConfigManager::init() {
loadConfigLoadVars();
@@ -159,17 +235,15 @@ void CConfigManager::init() {
void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) {
if (configValues.find(COMMAND) == configValues.end()) {
if (COMMAND[0] == '$') {
// register a dynamic var
Debug::log(LOG, "Registered dynamic var \"%s\" -> %s", COMMAND.c_str(), VALUE.c_str());
configDynamicVars[COMMAND.substr(1)] = VALUE;
} else {
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
}
if (COMMAND.find("device:") != 0 /* devices parsed later */) {
if (COMMAND[0] == '$') {
// register a dynamic var
Debug::log(LOG, "Registered dynamic var \"%s\" -> %s", COMMAND.c_str(), VALUE.c_str());
configDynamicVars[COMMAND.substr(1)] = VALUE;
} else {
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
}
if (COMMAND.find("device:") == 0 /* devices parsed later */) {
parseError = "";
} else {
return;
}
}
@@ -368,11 +442,15 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
return;
}
newrule.resolution.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
newrule.resolution.y = stoi(curitem.substr(curitem.find_first_of('x') + 1, curitem.find_first_of('@')));
if (curitem.find("pref") == 0) {
newrule.resolution = Vector2D();
} else {
newrule.resolution.x = stoi(curitem.substr(0, curitem.find_first_of('x')));
newrule.resolution.y = stoi(curitem.substr(curitem.find_first_of('x') + 1, curitem.find_first_of('@')));
if (curitem.contains("@"))
newrule.refreshRate = stof(curitem.substr(curitem.find_first_of('@') + 1));
if (curitem.contains("@"))
newrule.refreshRate = stof(curitem.substr(curitem.find_first_of('@') + 1));
}
nextItem();
@@ -436,6 +514,17 @@ void CConfigManager::handleBezier(const std::string& command, const std::string&
g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y));
}
void CConfigManager::setAnimForChildren(SAnimationPropertyConfig *const ANIM) {
for (auto& [name, anim] : animationConfig) {
if (anim.pParentAnimation == ANIM && !anim.overriden) {
// if a child isnt overriden, set the values of the parent
anim.pValues = ANIM->pValues;
setAnimForChildren(&anim);
}
}
};
void CConfigManager::handleAnimation(const std::string& command, const std::string& args) {
std::string curitem = "";
@@ -459,38 +548,73 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
// anim name
const auto ANIMNAME = curitem;
const auto ANIMMASTERSETTING = configValues.find("animations:" + ANIMNAME);
const auto PANIM = animationConfig.find(ANIMNAME);
if (ANIMMASTERSETTING == configValues.end()) {
Debug::log(ERR, "Anim %s doesnt exist", ANIMNAME.c_str());
parseError = "Animation " + ANIMNAME + " does not exist";
if (PANIM == animationConfig.end()) {
parseError = "no such animation";
return;
}
PANIM->second.overriden = true;
PANIM->second.pValues = &PANIM->second;
nextItem();
// on/off
configSetValueSafe("animations:" + ANIMNAME, curitem);
PANIM->second.internalEnabled = curitem == "1";
nextItem();
// Speed
configSetValueSafe("animations:" + ANIMNAME + "_speed", curitem);
// speed
if (isNumber(curitem, true)) {
PANIM->second.internalSpeed = std::stof(curitem);
} else {
PANIM->second.internalSpeed = 10.f;
parseError = "Invalid speed";
}
nextItem();
// curve
configSetValueSafe("animations:" + ANIMNAME + "_curve", curitem);
PANIM->second.internalBezier = curitem;
nextItem();
// style
configSetValueSafe("animations:" + ANIMNAME + "_style", curitem);
PANIM->second.internalStyle = curitem;
// now, check for children, recursively
setAnimForChildren(&PANIM->second);
}
void CConfigManager::handleBind(const std::string& command, const std::string& value, bool locked) {
void CConfigManager::handleBind(const std::string& command, const std::string& value) {
// example:
// bind=SUPER,G,exec,dmenu_run <args>
// bind[fl]=SUPER,G,exec,dmenu_run <args>
// flags
bool locked = false;
bool release = false;
bool repeat = false;
const auto ARGS = command.substr(4);
for (auto& arg : ARGS) {
if (arg == 'l') {
locked = true;
} else if (arg == 'r') {
release = true;
} else if (arg == 'e') {
repeat = true;
} else {
parseError = "bind: invalid flag";
return;
}
}
if (release && repeat) {
parseError = "flags r and e are mutually exclusive";
return;
}
auto valueCopy = value;
@@ -522,9 +646,9 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
if (KEY != "") {
if (isNumber(KEY) && std::stoi(KEY) > 9)
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap});
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat});
else
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap});
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat});
}
}
@@ -559,6 +683,7 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
&& RULE.find("monitor") != 0
&& RULE != "nofocus"
&& RULE != "noblur"
&& RULE != "center"
&& RULE != "fullscreen"
&& RULE.find("animation") != 0
&& RULE.find("rounding") != 0
@@ -573,6 +698,12 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
}
void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
if (value.find("remove,") == 0) {
const auto TOREMOVE = value.substr(7);
m_dBlurLSNamespaces.erase(std::remove(m_dBlurLSNamespaces.begin(), m_dBlurLSNamespaces.end(), TOREMOVE));
return;
}
m_dBlurLSNamespaces.emplace_back(value);
}
@@ -685,8 +816,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
}
}
else if (COMMAND == "monitor") handleMonitor(COMMAND, VALUE);
else if (COMMAND == "bind") handleBind(COMMAND, VALUE);
else if (COMMAND == "bindl") handleBind(COMMAND, VALUE, true);
else if (COMMAND.find("bind") == 0) handleBind(COMMAND, VALUE);
else if (COMMAND == "unbind") handleUnbind(COMMAND, VALUE);
else if (COMMAND == "workspace") handleDefaultWorkspace(COMMAND, VALUE);
else if (COMMAND == "windowrule") handleWindowRule(COMMAND, VALUE);
@@ -798,32 +928,42 @@ void CConfigManager::loadConfigLoadVars() {
configDynamicVars.clear();
deviceConfigs.clear();
m_dBlurLSNamespaces.clear();
setDefaultAnimationVars(); // reset anims
// paths
configPaths.clear();
std::string CONFIGPATH;
static const char* const ENVHOME = getenv("HOME");
const std::string CONFIGPARENTPATH = ENVHOME + (std::string) "/.config/hypr/";
const std::string CONFIGPATH = CONFIGPARENTPATH + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf");
if (g_pCompositor->explicitConfigPath == "") {
CONFIGPATH = CONFIGPARENTPATH + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf");
} else {
CONFIGPATH = g_pCompositor->explicitConfigPath;
}
configPaths.push_back(CONFIGPATH);
std::ifstream ifs;
ifs.open(CONFIGPATH);
if (!ifs.good()) {
Debug::log(WARN, "Config reading error. (No file? Attempting to generate, backing up old one if exists)");
try {
std::filesystem::rename(CONFIGPATH, CONFIGPATH + ".backup");
} catch(...) { /* Probably doesn't exist */}
if(g_pCompositor->explicitConfigPath == "") {
Debug::log(WARN, "Config reading error. (No file? Attempting to generate, backing up old one if exists)");
try {
std::filesystem::rename(CONFIGPATH, CONFIGPATH + ".backup");
} catch(...) { /* Probably doesn't exist */}
try {
if (!std::filesystem::is_directory(CONFIGPARENTPATH))
std::filesystem::create_directories(CONFIGPARENTPATH);
}
catch (...) {
parseError = "Broken config file! (Could not create directory)";
return;
try {
if (!std::filesystem::is_directory(CONFIGPARENTPATH))
std::filesystem::create_directories(CONFIGPARENTPATH);
}
catch (...) {
parseError = "Broken config file! (Could not create directory)";
return;
}
}
std::ofstream ofs;
@@ -870,8 +1010,10 @@ void CConfigManager::loadConfigLoadVars() {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
// Update the keyboard layout to the cfg'd one if this is not the first launch
if (!isFirstLaunch)
if (!isFirstLaunch) {
g_pInputManager->setKeyboardLayout();
g_pInputManager->setMouseConfigs();
}
// Calculate the internal vars
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue);
@@ -896,11 +1038,17 @@ void CConfigManager::loadConfigLoadVars() {
// and they'll be taken care of in the newMonitor event
if (!isFirstLaunch) {
m_bWantsMonitorReload = true;
// check
ensureDPMS();
}
// Update window border colors
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
// update layout
g_pLayoutManager->switchToLayout(configValues["general:layout"].strValue);
// Force the compositor to fully re-render all monitors
for (auto& m : g_pCompositor->m_vMonitors)
m->forceFullFrames = 2;
@@ -963,7 +1111,11 @@ SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, co
// fallback if not set explicitly
if (!copy.set) {
for (auto& cv : configValues) {
if (cv.first.find(val) == cv.first.length() - val.length()) {
auto foundIt = cv.first.find(val);
if (foundIt == std::string::npos)
continue;
if (foundIt == cv.first.length() - val.length()) {
copy = cv.second;
}
}
@@ -1099,6 +1251,15 @@ void CConfigManager::dispatchExecOnce() {
}
firstExecRequests.clear(); // free some kb of memory :P
// set input, fixes some certain issues
g_pInputManager->setKeyboardLayout();
g_pInputManager->setMouseConfigs();
// set ws names again
for (auto& ws : g_pCompositor->m_vWorkspaces) {
wlr_ext_workspace_handle_v1_set_name(ws->m_pWlrHandle, ws->m_szName.c_str());
}
}
void CConfigManager::performMonitorReload() {
@@ -1138,3 +1299,18 @@ bool CConfigManager::shouldBlurLS(const std::string& ns) {
return false;
}
void CConfigManager::ensureDPMS() {
for (auto& rm : g_pCompositor->m_vRealMonitors) {
auto rule = getMonitorRuleFor(rm->szName);
if (rule.disabled == rm->m_bEnabled) {
rm->m_pThisWrap = &rm;
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
}
}
}
SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::string& name) {
return &animationConfig[name];
}

View File

@@ -16,6 +16,9 @@
#define STRVAL_EMPTY "[[EMPTY]]"
#define INITANIMCFG(name) animationConfig[name] = {}
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
struct SConfigValue {
int64_t intValue = -1;
float floatValue = -1;
@@ -47,6 +50,18 @@ struct SWindowRule {
std::string szValue;
};
struct SAnimationPropertyConfig {
bool overriden = true;
std::string internalBezier = "";
std::string internalStyle = "";
float internalSpeed = 0.f;
int internalEnabled = -1;
SAnimationPropertyConfig* pValues = nullptr;
SAnimationPropertyConfig* pParentAnimation = nullptr;
};
class CConfigManager {
public:
CConfigManager();
@@ -84,6 +99,8 @@ public:
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
private:
std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
@@ -91,6 +108,8 @@ private:
std::unordered_map<std::string, SConfigValue> configValues;
std::unordered_map<std::string, std::unordered_map<std::string, SConfigValue>> deviceConfigs; // stores device configs
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
@@ -110,7 +129,11 @@ private:
// internal methods
void setDefaultVars();
void setDefaultAnimationVars();
void setDeviceDefaultVars(const std::string&);
void ensureDPMS();
void setAnimForChildren(SAnimationPropertyConfig *const);
void applyUserDefinedVars(std::string&, const size_t);
void loadConfigLoadVars();
@@ -121,7 +144,7 @@ private:
void handleDeviceConfig(const std::string&, const std::string&);
void handleRawExec(const std::string&, const std::string&);
void handleMonitor(const std::string&, const std::string&);
void handleBind(const std::string&, const std::string&, bool locked = false);
void handleBind(const std::string&, const std::string&);
void handleUnbind(const std::string&, const std::string&);
void handleWindowRule(const std::string&, const std::string&);
void handleDefaultWorkspace(const std::string&, const std::string&);

View File

@@ -9,9 +9,15 @@ PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
########################################################################################
#
# Please note not all available settings / options are set here.
# For a full list, see the wiki (basic and advanced configuring)
#
autogenerated=1 # remove this line to get rid of the warning on top.
monitor=,1920x1080@60,0x0,1
monitor=,preferred,0x0,1
input {
kb_layout=
@@ -21,6 +27,10 @@ input {
kb_rules=
follow_mouse=1
touchpad {
natural_scroll=no
}
}
general {
@@ -51,8 +61,8 @@ decoration {
animations {
enabled=1
animation=windows,1,7,default
animation=borders,1,10,default
animation=fadein,1,10,default
animation=border,1,10,default
animation=fade,1,10,default
animation=workspaces,1,6,default
}
@@ -60,6 +70,10 @@ dwindle {
pseudotile=0 # enable pseudotiling on dwindle
}
gestures {
workspace_swipe=no
}
# example window rules
# for windows named/classed as abc and xyz
#windowrule=move 69 420,abc
@@ -105,4 +119,7 @@ bind=ALT,7,movetoworkspace,7
bind=ALT,8,movetoworkspace,8
bind=ALT,9,movetoworkspace,9
bind=ALT,0,movetoworkspace,10
bind=SUPER,mouse_down,workspace,e+1
bind=SUPER,mouse_up,workspace,e-1
)#";

View File

@@ -13,95 +13,394 @@
#include <string>
std::string monitorsRequest() {
std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
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",
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"));
if (format == HyprCtl::FORMAT_JSON) {
result += "[";
for (auto& m : g_pCompositor->m_vMonitors) {
result += getFormat(
R"#({
"id": %i,
"name": "%s",
"width": %i,
"height": %i,
"refreshRate": %f,
"x": %i,
"y": %i,
"activeWorkspace": {
"id": %i,
"name": "%s"
},
"reserved": [%i, %i, %i, %i],
"scale": %.2f,
"transform": %i,
"active": "%s"
},)#",
m->ID,
escapeJSONStrings(m->szName).c_str(),
(int)m->vecPixelSize.x, (int)m->vecPixelSize.y,
m->refreshRate,
(int)m->vecPosition.x, (int)m->vecPosition.y,
m->activeWorkspace, escapeJSONStrings(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")
);
}
// remove trailing comma
result.pop_back();
result += "]";
} else {
for (auto& m : g_pCompositor->m_vMonitors) {
result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\tactive: %s\n\n",
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"));
}
}
return result;
}
std::string clientsRequest() {
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped) {
result += 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\n",
&w, w->m_szTitle.c_str(), (int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y, (int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w.get()).c_str(), g_pXWaylandManager->getTitle(w.get()).c_str(), w->getPID());
if (format == HyprCtl::FORMAT_JSON) {
result += "[";
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped) {
result += getFormat(
R"#({
"address": "0x%x",
"at": [%i, %i],
"size": [%i, %i],
"workspace": {
"id": %i,
"name": "%s"
},
"floating": %i,
"monitor": %i,
"class": "%s",
"title": "%s",
"pid": %i,
"xwayland": %i
},)#",
w.get(),
(int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y,
(int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y,
w->m_iWorkspaceID, escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))).c_str(),
(int)w->m_bIsFloating,
w->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(),
w->getPID(),
(int)w->m_bIsX11
);
}
}
// remove trailing comma
result.pop_back();
result += "]";
} else {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped) {
result += 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",
w.get(), w->m_szTitle.c_str(), (int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y, (int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y, w->m_iWorkspaceID, (w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)).c_str()), (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w.get()).c_str(), g_pXWaylandManager->getTitle(w.get()).c_str(), w->getPID(), (int)w->m_bIsX11);
}
}
}
return result;
}
std::string workspacesRequest() {
std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getFormat("workspace ID %i (%s) on monitor %s:\n\twindows: %i\n\thasfullscreen: %i\n\n",
w->m_iID, w->m_szName.c_str(), g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow);
if (format == HyprCtl::FORMAT_JSON) {
result += "[";
for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getFormat(
R"#({
"id": %i,
"name": "%s",
"monitor": "%s",
"windows": %i,
"hasfullscreen": %i
},)#",
w->m_iID,
escapeJSONStrings(w->m_szName).c_str(),
escapeJSONStrings(g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName).c_str(),
g_pCompositor->getWindowsOnWorkspace(w->m_iID),
(int)w->m_bHasFullscreenWindow
);
}
// remove trailing comma
result.pop_back();
result += "]";
} else {
for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getFormat("workspace ID %i (%s) on monitor %s:\n\twindows: %i\n\thasfullscreen: %i\n\n",
w->m_iID, w->m_szName.c_str(), g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow);
}
}
return result;
}
std::string activeWindowRequest() {
std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
return "Invalid";
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\n",
PWINDOW, PWINDOW->m_szTitle.c_str(), (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), (int)PWINDOW->m_bIsFloating, (int)PWINDOW->m_iMonitorID, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), g_pXWaylandManager->getTitle(PWINDOW).c_str(), PWINDOW->getPID());
if (format == HyprCtl::FORMAT_JSON) {
return getFormat(
R"#({
"address": "0x%x",
"at": [%i, %i],
"size": [%i, %i],
"workspace": {
"id": %i,
"name": "%s"
},
"floating": %i,
"monitor": %i,
"class": "%s",
"title": "%s",
"pid": %i,
"xwayland": %i
})#",
PWINDOW,
(int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y,
(int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y,
PWINDOW->m_iWorkspaceID, escapeJSONStrings(PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName).c_str(),
(int)PWINDOW->m_bIsFloating,
PWINDOW->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(),
PWINDOW->getPID(),
(int)PWINDOW->m_bIsX11
);
} 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",
PWINDOW, PWINDOW->m_szTitle.c_str(), (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), (int)PWINDOW->m_bIsFloating, (int)PWINDOW->m_iMonitorID, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), g_pXWaylandManager->getTitle(PWINDOW).c_str(), PWINDOW->getPID(), (int)PWINDOW->m_bIsX11);
}
}
std::string layersRequest() {
std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
for (auto& mon : g_pCompositor->m_vMonitors) {
result += getFormat("Monitor %s:\n", mon->szName.c_str());
int layerLevel = 0;
for (auto& level : mon->m_aLayerSurfaceLists) {
result += getFormat("\tLayer level %i:\n", layerLevel);
if (format == HyprCtl::FORMAT_JSON) {
result += "{\n";
for (auto& layer : level) {
result += getFormat("\t\tLayer %x: xywh: %i %i %i %i, namespace: %s\n", layer, layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, layer->szNamespace.c_str());
for (auto& mon : g_pCompositor->m_vMonitors) {
result += getFormat(
R"#("%s": {
"levels": {
)#",
escapeJSONStrings(mon->szName).c_str()
);
int layerLevel = 0;
for (auto& level : mon->m_aLayerSurfaceLists) {
result += getFormat(
R"#(
"%i": [
)#",
layerLevel
);
for (auto& layer : level) {
result += getFormat(
R"#( {
"address": "0x%x",
"x": %i,
"y": %i,
"w": %i,
"h": %i,
"namespace": "%s"
},)#",
layer.get(),
layer->geometry.x,
layer->geometry.y,
layer->geometry.width,
layer->geometry.height,
escapeJSONStrings(layer->szNamespace).c_str()
);
}
// remove trailing comma
result.pop_back();
if (level.size() > 0)
result += "\n ";
result += "],";
layerLevel++;
}
layerLevel++;
// remove trailing comma
result.pop_back();
result += "\n }\n},";
}
// remove trailing comma
result.pop_back();
result += "\n}\n";
} else {
for (auto& mon : g_pCompositor->m_vMonitors) {
result += getFormat("Monitor %s:\n", mon->szName.c_str());
int layerLevel = 0;
for (auto& level : mon->m_aLayerSurfaceLists) {
result += getFormat("\tLayer level %i:\n", layerLevel);
for (auto& layer : level) {
result += getFormat("\t\tLayer %x: xywh: %i %i %i %i, namespace: %s\n", layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, layer->szNamespace.c_str());
}
layerLevel++;
}
result += "\n\n";
}
result += "\n\n";
}
return result;
}
std::string devicesRequest() {
std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
result += "mice:\n";
if (format == HyprCtl::FORMAT_JSON) {
result += "{\n";
result += "\"mice\": [\n";
for (auto& m : g_pInputManager->m_lMice) {
result += getFormat("\tMouse at %x:\n\t\t%s\n", &m, m.mouse->name);
}
for (auto& m : g_pInputManager->m_lMice) {
result += getFormat(
R"#( {
"address": "0x%x",
"name": "%s"
},)#",
&m,
escapeJSONStrings(m.mouse->name).c_str()
);
}
result += "\n\nKeyboards:\n";
// remove trailing comma
result.pop_back();
result += "\n],\n";
for (auto& k : g_pInputManager->m_lKeyboards) {
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%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());
}
result += "\"keyboards\": [\n";
for (auto& k : g_pInputManager->m_lKeyboards) {
const auto KM = xkb_keymap_layout_get_name(wlr_keyboard_from_input_device(k.keyboard)->keymap, 0);
result += getFormat(
R"#( {
"address": "0x%x",
"name": "%s",
"rules": "%s",
"model": "%s",
"layout": "%s",
"variant": "%s",
"options": "%s",
"active_keymap": "%s"
},)#",
&k,
escapeJSONStrings(k.keyboard->name).c_str(),
escapeJSONStrings(k.currentRules.rules).c_str(),
escapeJSONStrings(k.currentRules.model).c_str(),
escapeJSONStrings(k.currentRules.layout).c_str(),
escapeJSONStrings(k.currentRules.variant).c_str(),
escapeJSONStrings(k.currentRules.options).c_str(),
escapeJSONStrings(KM).c_str()
);
}
result += "\n\nTablets:\n";
// remove trailing comma
result.pop_back();
result += "\n],\n";
for (auto& d : g_pInputManager->m_lTabletPads) {
result += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "");
}
result += "\"tablets\": [\n";
for (auto& d : g_pInputManager->m_lTablets) {
result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.wlrDevice ? d.wlrDevice->name : "");
}
for (auto& d : g_pInputManager->m_lTabletPads) {
result += getFormat(
R"#( {
"address": "0x%x",
"type": "tabletPad",
"belongsTo": {
"address": "0x%x",
"name": "%s"
}
},)#",
&d,
d.pTabletParent,
escapeJSONStrings(d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "").c_str()
);
}
for (auto& d : g_pInputManager->m_lTabletTools) {
result += getFormat("\tTablet Tool at %x (belongs to %x)\n", &d, d.wlrTabletTool ? d.wlrTabletTool->data : 0);
for (auto& d : g_pInputManager->m_lTablets) {
result += getFormat(
R"#( {
"address": "0x%x",
"name": "%s"
},)#",
&d,
escapeJSONStrings(d.wlrDevice ? d.wlrDevice->name : "").c_str()
);
}
for (auto& d : g_pInputManager->m_lTabletTools) {
result += getFormat(
R"#( {
"address": "0x%x",
"type": "tabletTool",
"belongsTo": "0x%x"
},)#",
&d,
d.wlrTabletTool ? d.wlrTabletTool->data : 0
);
}
// remove trailing comma
if (result[result.size() - 1] == ',')
result.pop_back();
result += "\n]\n";
result += "}\n";
} else {
result += "mice:\n";
for (auto& m : g_pInputManager->m_lMice) {
result += getFormat("\tMouse at %x:\n\t\t%s\n", &m, m.mouse->name);
}
result += "\n\nKeyboards:\n";
for (auto& k : g_pInputManager->m_lKeyboards) {
const auto KM = xkb_keymap_layout_get_name(wlr_keyboard_from_input_device(k.keyboard)->keymap, 0);
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n", &k, k.keyboard->name, k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM);
}
result += "\n\nTablets:\n";
for (auto& d : g_pInputManager->m_lTabletPads) {
result += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "");
}
for (auto& d : g_pInputManager->m_lTablets) {
result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.wlrDevice ? d.wlrDevice->name : "");
}
for (auto& d : g_pInputManager->m_lTabletTools) {
result += getFormat("\tTablet Tool at %x (belongs to %x)\n", &d, d.wlrTabletTool ? d.wlrTabletTool->data : 0);
}
}
return result;
@@ -161,6 +460,9 @@ std::string dispatchKeyword(std::string in) {
if (COMMAND.contains("input"))
g_pInputManager->setKeyboardLayout(); // update kb layout
if (COMMAND.contains("general:layout"))
g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout
Debug::log(LOG, "Hyprctl: keyword %s : %s", COMMAND.c_str(), VALUE.c_str());
if (retval == "")
@@ -220,24 +522,44 @@ std::string dispatchBatch(std::string request) {
}
std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL;
// process flags for non-batch requests
if (!request.contains("[[BATCH]]") && request.contains("/")) {
long unsigned int sepIndex = 0;
for (const auto& c : request) {
if (c == '/') { // stop at separator
break;
}
sepIndex++;
if (c == 'j')
format = HyprCtl::FORMAT_JSON;
}
if (sepIndex < request.size())
request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string
}
if (request == "monitors")
return monitorsRequest();
return monitorsRequest(format);
else if (request == "workspaces")
return workspacesRequest();
return workspacesRequest(format);
else if (request == "clients")
return clientsRequest();
return clientsRequest(format);
else if (request == "kill")
return killRequest();
else if (request == "activewindow")
return activeWindowRequest();
return activeWindowRequest(format);
else if (request == "layers")
return layersRequest();
return layersRequest(format);
else if (request == "version")
return versionRequest();
else if (request == "reload")
return reloadRequest();
else if (request == "devices")
return devicesRequest();
return devicesRequest(format);
else if (request == "splash")
return splashRequest();
else if (request.find("dispatch") == 0)
@@ -270,16 +592,7 @@ void HyprCtl::tickHyprCtl() {
}
std::string getRequestFromThread(std::string rq) {
// we need to do something to wake hyprland up if VFR is enabled
static auto *const PNOVFR = &g_pConfigManager->getConfigValuePtr("misc:no_vfr")->intValue;
// TODO: is this safe...?
// this might be a race condition
// tested with 2 instances of `watch -n 0.1 hyprctl splash` and seems to not crash so I'll take that as a yes
if (!*PNOVFR)
wlr_output_schedule_frame(g_pCompositor->m_vMonitors.front()->output);
while (HyprCtl::request != "" || HyprCtl::requestMade || HyprCtl::requestReady) {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}

View File

@@ -14,4 +14,9 @@ namespace HyprCtl {
inline std::string request = "";
inline std::ifstream requestStream;
enum eHyprCtlOutputFormat {
FORMAT_NORMAL = 0,
FORMAT_JSON
};
};

View File

@@ -1,7 +1,7 @@
#include "HyprDebugOverlay.hpp"
#include "../Compositor.hpp"
void CHyprMonitorDebugOverlay::renderData(SMonitor* pMonitor, float µs) {
void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
m_dLastRenderTimes.push_back(µs / 1000.f);
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
@@ -11,7 +11,7 @@ void CHyprMonitorDebugOverlay::renderData(SMonitor* pMonitor, float µs) {
m_pMonitor = pMonitor;
}
void CHyprMonitorDebugOverlay::renderDataNoOverlay(SMonitor* pMonitor, float µs) {
void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) {
m_dLastRenderTimesNoOverlay.push_back(µs / 1000.f);
if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
@@ -21,7 +21,7 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(SMonitor* pMonitor, float µs
m_pMonitor = pMonitor;
}
void CHyprMonitorDebugOverlay::frameData(SMonitor* pMonitor) {
void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) {
m_dLastFrametimes.push_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate)
@@ -126,15 +126,15 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
return yOffset - offset;
}
void CHyprDebugOverlay::renderData(SMonitor* pMonitor, float µs) {
void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
m_mMonitorOverlays[pMonitor].renderData(pMonitor, µs);
}
void CHyprDebugOverlay::renderDataNoOverlay(SMonitor* pMonitor, float µs) {
void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) {
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, µs);
}
void CHyprDebugOverlay::frameData(SMonitor* pMonitor) {
void CHyprDebugOverlay::frameData(CMonitor* pMonitor) {
m_mMonitorOverlays[pMonitor].frameData(pMonitor);
}

View File

@@ -11,16 +11,16 @@ class CHyprMonitorDebugOverlay {
public:
int draw(int offset);
void renderData(SMonitor* pMonitor, float µs);
void renderDataNoOverlay(SMonitor* pMonitor, float µs);
void frameData(SMonitor* pMonitor);
void renderData(CMonitor* pMonitor, float µs);
void renderDataNoOverlay(CMonitor* pMonitor, float µs);
void frameData(CMonitor* pMonitor);
private:
std::deque<float> m_dLastFrametimes;
std::deque<float> m_dLastRenderTimes;
std::deque<float> m_dLastRenderTimesNoOverlay;
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
SMonitor* m_pMonitor = nullptr;
CMonitor* m_pMonitor = nullptr;
wlr_box m_wbLastDrawnBox;
};
@@ -28,13 +28,13 @@ class CHyprDebugOverlay {
public:
void draw();
void renderData(SMonitor*, float µs);
void renderDataNoOverlay(SMonitor*, float µs);
void frameData(SMonitor*);
void renderData(CMonitor*, float µs);
void renderDataNoOverlay(CMonitor*, float µs);
void frameData(CMonitor*);
private:
std::unordered_map<SMonitor*, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
std::unordered_map<CMonitor*, CHyprMonitorDebugOverlay> m_mMonitorOverlays;
cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr;

View File

@@ -41,37 +41,37 @@ void Debug::log(LogLevel level, const char* fmt, ...) {
break;
}
char buf[LOGMESSAGESIZE] = "";
char* outputStr;
int logLen;
// print date and time to the ofs
if (disableTime && !*disableTime) {
auto timet = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
const auto MILLIS = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() % 1000;
ofs << std::put_time(std::localtime(&timet), "[%H:%M:%S:");
if (MILLIS > 99)
ofs << MILLIS;
else if (MILLIS > 9)
ofs << "0" << MILLIS;
else
ofs << "00" << MILLIS;
ofs << "] ";
}
char* outputStr = nullptr;
va_list args;
va_start(args, fmt);
logLen = vsnprintf(buf, sizeof buf, fmt, args);
vasprintf(&outputStr, fmt, args);
va_end(args);
if ((long unsigned int)logLen < sizeof buf) {
outputStr = strdup(buf);
} else {
outputStr = (char*)malloc(logLen + 1);
std::string output = std::string(outputStr);
free(outputStr);
if (!outputStr) {
printf("CRITICAL: Cannot alloc size %d for log! (Out of memory?)", logLen + 1);
return;
}
va_start(args, fmt);
vsnprintf(outputStr, logLen + 1U, fmt, args);
va_end(args);
}
ofs << outputStr << "\n";
ofs << output << "\n";
ofs.close();
// log it to the stdout too.
std::cout << outputStr << "\n";
// free the log
free(outputStr);
std::cout << output << "\n";
}

View File

@@ -18,4 +18,5 @@ namespace Debug {
inline std::string logFile;
inline int64_t* disableLogs = nullptr;
inline int64_t* disableTime = nullptr;
};

View File

@@ -54,6 +54,12 @@
#define ASSERT(expr) RASSERT(expr, "?")
#if ISDEBUG
#define UNREACHABLE() { Debug::log(CRIT, "\n\nMEMORY CORRUPTED: Unreachable failed! (Reached an unreachable position, memory corruption!!!)"); *((int*)nullptr) = 1; }
#else
#define UNREACHABLE() std::unreachable();
#endif
// git stuff
#ifndef GIT_COMMIT_HASH
#define GIT_COMMIT_HASH "?"

View File

@@ -49,9 +49,7 @@ void Events::listener_mouseButton(wl_listener* listener, void* data) {
}
void Events::listener_mouseAxis(wl_listener* listener, void* data) {
const auto E = (wlr_pointer_axis_event*)data;
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, E->time_msec, E->orientation, E->delta, E->delta_discrete, E->source);
g_pInputManager->onMouseWheel((wlr_pointer_axis_event*)data);
}
void Events::listener_requestMouse(wl_listener* listener, void* data) {
@@ -177,3 +175,18 @@ void Events::listener_swipeEnd(wl_listener* listener, void* data) {
g_pInputManager->onSwipeEnd(EVENT);
}
void Events::listener_pinchBegin(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_pinch_begin_event*)data;
wlr_pointer_gestures_v1_send_pinch_begin(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, EV->time_msec, EV->fingers);
}
void Events::listener_pinchUpdate(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_pinch_update_event*)data;
wlr_pointer_gestures_v1_send_pinch_update(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, EV->time_msec, EV->dx, EV->dy, EV->scale, EV->rotation);
}
void Events::listener_pinchEnd(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_pinch_end_event*)data;
wlr_pointer_gestures_v1_send_pinch_end(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, EV->time_msec, EV->cancelled);
}

View File

@@ -50,6 +50,10 @@ namespace Events {
DYNLISTENFUNC(activateX11);
DYNLISTENFUNC(configureX11);
DYNLISTENFUNC(unmanagedSetGeometry);
DYNLISTENFUNC(requestMove);
DYNLISTENFUNC(requestResize);
DYNLISTENFUNC(requestMinimize);
DYNLISTENFUNC(requestMaximize);
// Window subsurfaces
// LISTENER(newSubsurfaceWindow);
@@ -116,7 +120,17 @@ namespace Events {
LISTENER(newIdleInhibitor);
// session
LISTENER(sessionActive);
// Touchpad shit
LISTENER(swipeBegin);
LISTENER(swipeEnd);
LISTENER(swipeUpdate);
LISTENER(pinchBegin);
LISTENER(pinchUpdate);
LISTENER(pinchEnd);
// Power
LISTENER(powerMgrSetMode);
};

View File

@@ -31,8 +31,8 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
WLRLAYERSURFACE->output = PMONITOR->output;
}
const auto PMONITOR = (SMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output);
SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].emplace_back(new SLayerSurface());
const auto PMONITOR = (CMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output);
SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].emplace_back(std::make_unique<SLayerSurface>()).get();
layerSurface->szNamespace = WLRLAYERSURFACE->_namespace;
@@ -41,7 +41,7 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
}
layerSurface->hyprListener_commitLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.commit, &Events::listener_commitLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_unmapLayerSurface.initCallback(&WLRLAYERSURFACE->events.unmap, &Events::listener_unmapLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_newPopup.initCallback(&WLRLAYERSURFACE->events.new_popup, &Events::listener_newPopup, layerSurface, "layerSurface");
@@ -66,12 +66,20 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID))
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
if (!layersurface->fadingOut && PMONITOR) {
Debug::log(LOG, "Removing LayerSurface that wasn't mapped.");
layersurface->alpha.setValueAndWarp(0.f);
layersurface->fadingOut = true;
if (!layersurface->fadingOut) {
if (layersurface->mapped) {
Debug::log(LOG, "Forcing an unmap of a LS that did a straight destroy!");
listener_unmapLayerSurface(layersurface, nullptr);
} else {
Debug::log(LOG, "Removing LayerSurface that wasn't mapped.");
layersurface->alpha.setValueAndWarp(0.f);
layersurface->fadingOut = true;
g_pCompositor->addToFadingOutSafe(layersurface);
}
}
layersurface->noProcess = true;
layersurface->hyprListener_commitLayerSurface.removeCallback();
layersurface->hyprListener_destroyLayerSurface.removeCallback();
layersurface->hyprListener_mapLayerSurface.removeCallback();
@@ -81,7 +89,7 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
// rearrange to fix the reserved areas
if (PMONITOR) {
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
PMONITOR->scheduledRecalc = true;
// and damage
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height};
@@ -98,8 +106,10 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
Debug::log(LOG, "LayerSurface %x mapped", layersurface->layerSurface);
layersurface->layerSurface->mapped = true;
layersurface->mapped = true;
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
// anim
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
// fix if it changed its mon
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
@@ -109,22 +119,28 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
if ((uint64_t)layersurface->monitorID != PMONITOR->ID) {
const auto POLDMON = g_pCompositor->getMonitorFromID(layersurface->monitorID);
POLDMON->m_aLayerSurfaceLists[layersurface->layer].remove(layersurface);
PMONITOR->m_aLayerSurfaceLists[layersurface->layer].push_back(layersurface);
for (auto it = POLDMON->m_aLayerSurfaceLists[layersurface->layer].begin(); it != POLDMON->m_aLayerSurfaceLists[layersurface->layer].end(); it++) {
if (it->get() == layersurface) {
PMONITOR->m_aLayerSurfaceLists[layersurface->layer].emplace_back(std::move(*it));
POLDMON->m_aLayerSurfaceLists[layersurface->layer].erase(it);
break;
}
}
layersurface->monitorID = PMONITOR->ID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
PMONITOR->scheduledRecalc = true;
g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID);
}
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint)) // don't focus if constrained
if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint)) { // don't focus if constrained
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
g_pCompositor->focusSurface(layersurface->layerSurface->surface);
// mouse enter always, keeb only when needed
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y);
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y);
}
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
@@ -144,16 +160,29 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID)) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
g_pCompositor->addToFadingOutSafe(layersurface);
layersurface->mapped = false;
layersurface->fadingOut = true;
layersurface->alpha.setValueAndWarp(0.f);
return;
}
// anim
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut"));
// make a snapshot and start fade
g_pHyprOpenGL->makeLayerSnapshot(layersurface);
layersurface->alpha = 0.f;
layersurface->mapped = false;
layersurface->fadingOut = true;
g_pCompositor->m_vSurfacesFadingOut.push_back(layersurface);
g_pCompositor->addToFadingOutSafe(layersurface);
if (layersurface->layerSurface->mapped)
layersurface->layerSurface->mapped = false;
@@ -196,23 +225,37 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
// fix if it changed its mon
if ((uint64_t)layersurface->monitorID != PMONITOR->ID) {
const auto POLDMON = g_pCompositor->getMonitorFromID(layersurface->monitorID);
POLDMON->m_aLayerSurfaceLists[layersurface->layer].remove(layersurface);
PMONITOR->m_aLayerSurfaceLists[layersurface->layer].push_back(layersurface);
for (auto it = POLDMON->m_aLayerSurfaceLists[layersurface->layer].begin(); it != POLDMON->m_aLayerSurfaceLists[layersurface->layer].end(); it++) {
if (it->get() == layersurface) {
PMONITOR->m_aLayerSurfaceLists[layersurface->layer].emplace_back(std::move(*it));
POLDMON->m_aLayerSurfaceLists[layersurface->layer].erase(it);
break;
}
}
layersurface->monitorID = PMONITOR->ID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
PMONITOR->scheduledRecalc = true;
g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID);
}
if (layersurface->layerSurface->current.committed != 0) {
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
if (layersurface->layer != layersurface->layerSurface->current.layer) {
PMONITOR->m_aLayerSurfaceLists[layersurface->layer].remove(layersurface);
PMONITOR->m_aLayerSurfaceLists[layersurface->layerSurface->current.layer].push_back(layersurface);
for (auto it = PMONITOR->m_aLayerSurfaceLists[layersurface->layer].begin(); it != PMONITOR->m_aLayerSurfaceLists[layersurface->layer].end(); it++) {
if (it->get() == layersurface) {
PMONITOR->m_aLayerSurfaceLists[layersurface->layerSurface->current.layer].emplace_back(std::move(*it));
PMONITOR->m_aLayerSurfaceLists[layersurface->layer].erase(it);
break;
}
}
layersurface->layer = layersurface->layerSurface->current.layer;
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
PMONITOR->scheduledRecalc = true;
}
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);

View File

@@ -157,4 +157,21 @@ void Events::listener_InhibitDeactivate(wl_listener* listener, void* data) {
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
Debug::log(LOG, "!!Renderer destroyed!!");
}
void Events::listener_sessionActive(wl_listener* listener, void* data) {
Debug::log(LOG, "Session got activated!");
g_pCompositor->m_bSessionActive = true;
}
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
Debug::log(LOG, "PowerMgr set mode!");
const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
wlr_output_enable(EVENT->output, EVENT->mode == 1);
if (!wlr_output_commit(EVENT->output))
Debug::log(ERR, "Couldn't set power mode");
}

View File

@@ -15,7 +15,7 @@
// //
// --------------------------------------------------------- //
SMonitor* pMostHzMonitor = nullptr;
CMonitor* pMostHzMonitor = nullptr;
void Events::listener_change(wl_listener* listener, void* data) {
// layout got changed, let's update monitors.
@@ -58,113 +58,34 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
return;
}
// get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(OUTPUT->name);
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
wlr_output_enable(OUTPUT, 0);
wlr_output_commit(OUTPUT);
if (const auto PMONITOR = g_pCompositor->getMonitorFromName(std::string(OUTPUT->name)); PMONITOR) {
listener_monitorDestroy(nullptr, PMONITOR->output);
}
return;
}
SMonitor newMonitor;
newMonitor.output = OUTPUT;
newMonitor.ID = g_pCompositor->getNextAvailableMonitorID();
newMonitor.szName = OUTPUT->name;
// add it to real
const auto PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
wlr_output_init_render(OUTPUT, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
wlr_output_set_scale(OUTPUT, monitorRule.scale);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
wlr_output_set_transform(OUTPUT, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms
PNEWMONITOR->output = OUTPUT;
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
wlr_output_enable_adaptive_sync(OUTPUT, 1);
PNEWMONITOR->onConnect(false);
// create it in the arr
newMonitor.vecPosition = monitorRule.offset;
newMonitor.vecSize = monitorRule.resolution;
newMonitor.refreshRate = monitorRule.refreshRate;
const auto PNEWMONITOR = g_pCompositor->m_vMonitors.emplace_back(std::make_unique<SMonitor>(newMonitor)).get();
PNEWMONITOR->hyprListener_monitorFrame.initCallback(&OUTPUT->events.frame, &Events::listener_monitorFrame, PNEWMONITOR);
PNEWMONITOR->hyprListener_monitorDestroy.initCallback(&OUTPUT->events.destroy, &Events::listener_monitorDestroy, PNEWMONITOR);
wlr_output_enable(OUTPUT, 1);
// TODO: this doesn't seem to set the X and Y correctly,
// wlr_output_layout_output_coords returns invalid values, I think...
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, OUTPUT, monitorRule.offset.x, monitorRule.offset.y);
// set mode, also applies
g_pHyprRenderer->applyMonitorRule(PNEWMONITOR, &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);
PNEWMONITOR->damage = wlr_output_damage_create(PNEWMONITOR->output);
// add a WLR workspace group
PNEWMONITOR->pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
wlr_ext_workspace_group_handle_v1_output_enter(PNEWMONITOR->pWLRWorkspaceGroupHandle, PNEWMONITOR->output);
// Workspace
std::string newDefaultWorkspaceName = "";
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace);
}
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, PNEWMONITOR);
PNEWMONITOR->activeWorkspace = PNEWWORKSPACE->m_iID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PNEWMONITOR->ID);
PNEWWORKSPACE->startAnim(true,true,true);
} else {
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(newMonitor.ID, newDefaultWorkspaceName)).get();
// We are required to set the name here immediately
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
PNEWWORKSPACE->m_iID = WORKSPACEID;
}
PNEWMONITOR->activeWorkspace = PNEWWORKSPACE->m_iID;
PNEWMONITOR->scale = monitorRule.scale;
PNEWMONITOR->forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
PNEWWORKSPACE->setActive(true);
//
if (!pMostHzMonitor || monitorRule.refreshRate > pMostHzMonitor->refreshRate)
if (!pMostHzMonitor || PNEWMONITOR->refreshRate > pMostHzMonitor->refreshRate)
pMostHzMonitor = PNEWMONITOR;
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->m_pLastMonitor = PNEWMONITOR;
g_pEventManager->postEvent(SHyprIPCEvent("monitoradded", PNEWMONITOR->szName));
// ready to process cuz we have a monitor
g_pCompositor->m_bReadyToProcess = true;
}
void Events::listener_monitorFrame(void* owner, void* data) {
SMonitor* const PMONITOR = (SMonitor*)owner;
CMonitor* const PMONITOR = (CMonitor*)owner;
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive) {
Debug::log(WARN, "Attempted to render frame on inactive session!");
return; // cannot draw on session inactive (different tty)
}
if (!PMONITOR->m_bEnabled)
return;
static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now();
static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now();
@@ -177,18 +98,33 @@ void Events::listener_monitorFrame(void* owner, void* data) {
static int damageBlinkCleanup = 0; // because double-buffered
if (!*PDAMAGEBLINK)
damageBlinkCleanup = 0;
if (*PDEBUGOVERLAY == 1) {
startRender = std::chrono::high_resolution_clock::now();
g_pDebugOverlay->frameData(PMONITOR);
}
if (PMONITOR->framesToSkip > 0) {
PMONITOR->framesToSkip -= 1;
if (!PMONITOR->noFrameSchedule)
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
else {
Debug::log(LOG, "NoFrameSchedule hit for %s.", PMONITOR->szName.c_str());
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
if (PMONITOR->framesToSkip > 10)
PMONITOR->framesToSkip = 0;
return;
}
// checks //
if (PMONITOR->ID == pMostHzMonitor->ID || !*PNOVFR) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that
g_pCompositor->sanityCheckWorkspaces();
g_pAnimationManager->tick();
g_pCompositor->cleanupFadingOut();
HyprCtl::tickHyprCtl(); // so that we dont get that race condition multithread bullshit
g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
@@ -199,16 +135,9 @@ void Events::listener_monitorFrame(void* owner, void* data) {
}
// //
if (PMONITOR->framesToSkip > 0) {
PMONITOR->framesToSkip -= 1;
if (!PMONITOR->noFrameSchedule)
wlr_output_schedule_frame(PMONITOR->output);
else {
Debug::log(LOG, "NoFrameSchedule hit for %s.", PMONITOR->szName.c_str());
}
if (PMONITOR->scheduledRecalc) {
PMONITOR->scheduledRecalc = false;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
return;
}
timespec now;
@@ -229,12 +158,15 @@ void Events::listener_monitorFrame(void* owner, void* data) {
return;
}
// we need to cleanup fading out when rendering the appropriate context
g_pCompositor->cleanupFadingOut(PMONITOR->ID);
if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && PMONITOR->forceFullFrames == 0 && damageBlinkCleanup == 0) {
pixman_region32_fini(&damage);
wlr_output_rollback(PMONITOR->output);
if (*PDAMAGEBLINK || *PNOVFR)
wlr_output_schedule_frame(PMONITOR->output);
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
return;
}
@@ -263,8 +195,12 @@ void Events::listener_monitorFrame(void* owner, void* data) {
}
}
if (PMONITOR->forceFullFrames > 0)
if (PMONITOR->forceFullFrames > 0) {
PMONITOR->forceFullFrames -= 1;
if (PMONITOR->forceFullFrames > 10)
PMONITOR->forceFullFrames = 0;
}
// TODO: this is getting called with extents being 0,0,0,0 should it be?
// potentially can save on resources.
@@ -324,7 +260,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
wlr_output_commit(PMONITOR->output);
if (*PDAMAGEBLINK || *PNOVFR)
wlr_output_schedule_frame(PMONITOR->output);
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
if (*PDEBUGOVERLAY == 1) {
const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
@@ -341,7 +277,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
void Events::listener_monitorDestroy(void* owner, void* data) {
const auto OUTPUT = (wlr_output*)data;
SMonitor* pMonitor = nullptr;
CMonitor* pMonitor = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->szName == OUTPUT->name) {
@@ -353,47 +289,14 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
if (!pMonitor)
return;
// Cleanup everything. Move windows back, snap cursor, shit.
const auto BACKUPMON = g_pCompositor->m_vMonitors.front().get();
pMonitor->onDisconnect();
if (!BACKUPMON) {
Debug::log(CRIT, "No monitors! Unplugged last! Exiting.");
g_pCompositor->cleanupExit();
exit(1);
return;
}
const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;
// snap cursor
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
// move workspaces
std::deque<CWorkspace*> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == pMonitor->ID) {
wspToMove.push_back(w.get());
}
}
for (auto& w : wspToMove) {
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
w->startAnim(true, true, true);
}
pMonitor->activeWorkspace = -1;
g_pCompositor->m_vWorkspaces.erase(std::remove_if(g_pCompositor->m_vWorkspaces.begin(), g_pCompositor->m_vWorkspaces.end(), [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == pMonitor->ID; }));
Debug::log(LOG, "Removed monitor %s!", pMonitor->szName.c_str());
g_pEventManager->postEvent(SHyprIPCEvent("monitorremoved", pMonitor->szName));
g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](std::unique_ptr<SMonitor>& el) { return el.get() == pMonitor; }));
// cleanup
g_pCompositor->m_vRealMonitors.erase(std::remove_if(g_pCompositor->m_vRealMonitors.begin(), g_pCompositor->m_vRealMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; }));
if (pMostHzMonitor == pMonitor) {
int mostHz = 0;
SMonitor* pMonitorMostHz = nullptr;
CMonitor* pMonitorMostHz = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->refreshRate > mostHz) {

View File

@@ -51,14 +51,15 @@ void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
pHyprPopup->popup = popup;
pHyprPopup->hyprListener_destroyPopupXDG.initCallback(&popup->base->surface->events.destroy, &Events::listener_destroyPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_destroyPopupXDG.initCallback(&popup->base->events.destroy, &Events::listener_destroyPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_mapPopupXDG.initCallback(&popup->base->events.map, &Events::listener_mapPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_unmapPopupXDG.initCallback(&popup->base->events.unmap, &Events::listener_unmapPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_newPopupFromPopupXDG.initCallback(&popup->base->events.new_popup, &Events::listener_newPopupFromPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_commitPopupXDG.initCallback(&popup->base->surface->events.commit, &Events::listener_commitPopupXDG, pHyprPopup, "HyprPopup");
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->vecSize.x, .height = PMONITOR->vecSize.y};
wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->vecTransformedSize.x, .height = PMONITOR->vecTransformedSize.y};
wlr_xdg_popup_unconstrain_from_box(popup, &box);
@@ -103,9 +104,12 @@ void Events::listener_newPopupXDG(void* owner, void* data) {
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->lx = PWINDOW->m_vRealPosition.goalv().x;
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y;
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x - geom.x;
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y - geom.y;
PNEWPOPUP->parentWindow = PWINDOW;
PNEWPOPUP->monitor = PMONITOR;
createNewPopup(WLRPOPUP, PNEWPOPUP);
@@ -144,6 +148,11 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow);
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
g_pHyprRenderer->damageBox(lx, ly, PPOPUP->popup->current.geometry.width, PPOPUP->popup->current.geometry.width);
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree);
}
@@ -155,9 +164,23 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
g_pHyprRenderer->damageBox(lx, ly, PPOPUP->popup->current.geometry.width, PPOPUP->popup->current.geometry.width);
PPOPUP->pSurfaceTree = nullptr;
}
void Events::listener_commitPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
g_pHyprRenderer->damageSurface(PPOPUP->popup->base->surface, lx, ly);
}
void Events::listener_destroyPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;

View File

@@ -29,6 +29,20 @@ void addViewCoords(void* pWindow, int* x, int* y) {
}
}
int setAnimToMove(void* data) {
const auto PWINDOW = (CWindow*)data;
auto *const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
if (!g_pCompositor->windowValidMapped(PWINDOW))
return 0;
PWINDOW->m_vRealPosition.setConfig(PANIMCFG);
PWINDOW->m_vRealSize.setConfig(PANIMCFG);
return 0;
}
void Events::listener_mapWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
@@ -44,11 +58,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bReadyToDelete = false;
PWINDOW->m_bFadingOut = false;
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
PWINDOW->m_fAlpha = 255.f;
if (PWINDOW->m_iX11Type == 2)
g_pCompositor->moveUnmanagedX11ToWindows(PWINDOW);
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
// Set all windows tiled regardless of anything
g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
@@ -206,6 +221,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
PWINDOW->m_bHidden = false;
} catch (...) {
Debug::log(LOG, "Rule size failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
}
@@ -221,9 +238,13 @@ void Events::listener_mapWindow(void* owner, void* data) {
Debug::log(LOG, "Rule move, applying to window %x", PWINDOW);
PWINDOW->m_vRealPosition = Vector2D(POSX, POSY) + PMONITOR->vecPosition;
PWINDOW->m_bHidden = false;
} catch (...) {
Debug::log(LOG, "Rule move failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
}
} else if (r.szRule == "center") {
PWINDOW->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.f - PWINDOW->m_vRealSize.goalv() / 2.f;
}
}
@@ -251,6 +272,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
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_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_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");
} else {
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");
@@ -263,6 +288,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
// do the animation thing
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
PWINDOW->m_fAlpha = 255.f;
const auto TIMER = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, setAnimToMove, PWINDOW);
wl_event_source_timer_update(TIMER, PWINDOW->m_vRealPosition.getDurationLeftMs() + 5);
if (workspaceSilent) {
// move the window
@@ -304,13 +334,17 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "Window %x unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
if (!PWINDOW->m_bIsX11) {
Debug::log(LOG, "Unregistered late callbacks XDG: %x %x %x %x", &PWINDOW->hyprListener_commitWindow.m_sListener.link, &PWINDOW->hyprListener_setTitleWindow.m_sListener.link, &PWINDOW->hyprListener_fullscreenWindow.m_sListener.link, &PWINDOW->hyprListener_newPopupXDG.m_sListener.link);
Debug::log(LOG, "Unregistered late callbacks XDG");
PWINDOW->hyprListener_commitWindow.removeCallback();
PWINDOW->hyprListener_setTitleWindow.removeCallback();
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
PWINDOW->hyprListener_newPopupXDG.removeCallback();
PWINDOW->hyprListener_requestMaximize.removeCallback();
PWINDOW->hyprListener_requestMinimize.removeCallback();
PWINDOW->hyprListener_requestMove.removeCallback();
PWINDOW->hyprListener_requestResize.removeCallback();
} else {
Debug::log(LOG, "Unregistered late callbacks XWL: %x %x %x %x", &PWINDOW->hyprListener_fullscreenWindow.m_sListener.link, &PWINDOW->hyprListener_activateX11.m_sListener.link, &PWINDOW->hyprListener_configureX11.m_sListener.link, &PWINDOW->hyprListener_setTitleWindow.m_sListener.link);
Debug::log(LOG, "Unregistered late callbacks XWL");
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
PWINDOW->hyprListener_activateX11.removeCallback();
PWINDOW->hyprListener_configureX11.removeCallback();
@@ -331,8 +365,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pCompositor->m_pLastFocus = nullptr;
}
PWINDOW->m_fAlpha = 0.f;
PWINDOW->m_bMappedX11 = false;
// remove the fullscreen window status from workspace if we closed it
@@ -356,7 +388,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->m_bFadingOut = true;
g_pCompositor->m_vWindowsFadingOut.emplace_back(PWINDOW);
g_pCompositor->addToFadingOutSafe(PWINDOW);
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
@@ -368,7 +400,10 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.vec() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
// anims
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true);
PWINDOW->m_fAlpha = 0.f;
// Destroy Foreign Toplevel
wlr_foreign_toplevel_handle_v1_destroy(PWINDOW->m_phForeignToplevel);
@@ -426,7 +461,7 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
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)
wlr_foreign_toplevel_handle_v1_set_title(PWINDOW->m_phForeignToplevel, PWINDOW->m_szTitle.c_str());
@@ -442,6 +477,8 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen)
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, REQUESTED->fullscreen);
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
} else {
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, !PWINDOW->m_bIsFullscreen);
}
@@ -484,6 +521,11 @@ void Events::listener_configureX11(void* owner, void* data) {
return;
}
if (E->width > 1 && E->height > 1)
PWINDOW->m_bHidden = false;
else
PWINDOW->m_bHidden = true;
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(E->x, E->y));
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height));
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
@@ -491,6 +533,8 @@ void Events::listener_configureX11(void* owner, void* data) {
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
g_pCompositor->moveWindowToTop(PWINDOW);
PWINDOW->m_bCreatedOverFullscreen = true;
@@ -498,6 +542,8 @@ void Events::listener_configureX11(void* owner, void* data) {
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->updateWindowDecos();
}
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
@@ -509,14 +555,22 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
const auto POS = PWINDOW->m_vRealPosition.goalv();
const auto SIZ = PWINDOW->m_vRealSize.goalv();
if (abs(floor(POS.x) - PWINDOW->m_uSurface.xwayland->x) > 2 || abs(floor(POS.y) - PWINDOW->m_uSurface.xwayland->y) > 2 || abs(floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) {
if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1)
PWINDOW->m_bHidden = false;
else
PWINDOW->m_bHidden = true;
if (abs(std::floor(POS.x) - PWINDOW->m_uSurface.xwayland->x) > 2 || abs(std::floor(POS.y) - PWINDOW->m_uSurface.xwayland->y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) {
Debug::log(LOG, "Unmanaged window %x requests geometry update to %i %i %i %i", PWINDOW, (int)PWINDOW->m_uSurface.xwayland->x, (int)PWINDOW->m_uSurface.xwayland->y, (int)PWINDOW->m_uSurface.xwayland->width, (int)PWINDOW->m_uSurface.xwayland->height);
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y));
if (abs(floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2)
if (abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2)
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height));
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec());
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
g_pCompositor->moveWindowToTop(PWINDOW);
PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW);
@@ -547,10 +601,10 @@ void Events::listener_newXDGSurface(wl_listener* listener, void* data) {
// A window got opened
const auto XDGSURFACE = (wlr_xdg_surface*)data;
Debug::log(LOG, "New XDG Surface created. (class: %s)", XDGSURFACE->toplevel->app_id);
if (XDGSURFACE->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
return; // TODO: handle?
return;
Debug::log(LOG, "New XDG Surface created. (class: %s)", XDGSURFACE->toplevel->app_id);
const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(std::make_unique<CWindow>()).get();
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
@@ -564,3 +618,28 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
const auto WLRDECO = (wlr_xdg_toplevel_decoration_v1*)data;
wlr_xdg_toplevel_decoration_v1_set_mode(WLRDECO, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
void Events::listener_requestMaximize(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner;
// ignore
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
}
void Events::listener_requestMinimize(void* owner, void* data) {
// ignore
}
void Events::listener_requestMove(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner;
// ignore
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
}
void Events::listener_requestResize(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner;
// ignore
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
}

View File

@@ -1,25 +1,24 @@
#include "AnimatedVariable.hpp"
#include "../managers/AnimationManager.hpp"
#include "../config/ConfigManager.hpp"
CAnimatedVariable::CAnimatedVariable() {
; // dummy var
}
void CAnimatedVariable::create(ANIMATEDVARTYPE type, float* speed, int64_t* enabled, std::string* pBezier, void* pWindow, AVARDAMAGEPOLICY policy) {
void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
m_eVarType = type;
m_eDamagePolicy = policy;
m_pSpeed = speed;
m_pEnabled = enabled;
m_pConfig = pAnimConfig;
m_pWindow = pWindow;
m_pBezier = pBezier;
g_pAnimationManager->m_lAnimatedVariables.push_back(this);
m_bDummy = false;
}
void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, float* speed, int64_t* enabled, std::string* pBezier, void* pWindow, AVARDAMAGEPOLICY policy) {
create(type, speed, enabled, pBezier, pWindow, policy);
void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
create(type, pAnimConfig, pWindow, policy);
try {
switch (type) {
@@ -57,4 +56,8 @@ CAnimatedVariable::~CAnimatedVariable() {
void CAnimatedVariable::unregister() {
g_pAnimationManager->m_lAnimatedVariables.remove(this);
}
}
int CAnimatedVariable::getDurationLeftMs() {
return std::clamp((int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0, INT_MAX);
}

View File

@@ -13,19 +13,21 @@ enum ANIMATEDVARTYPE {
enum AVARDAMAGEPOLICY {
AVARDAMAGE_INVALID = -1,
AVARDAMAGE_ENTIRE = 0,
AVARDAMAGE_BORDER
AVARDAMAGE_BORDER,
AVARDAMAGE_SHADOW
};
class CAnimationManager;
class CWorkspace;
struct SLayerSurface;
struct SAnimationPropertyConfig;
class CAnimatedVariable {
public:
CAnimatedVariable(); // dummy var
void create(ANIMATEDVARTYPE, float* speed, int64_t* enabled, std::string* pBezier, void* pWindow, AVARDAMAGEPOLICY);
void create(ANIMATEDVARTYPE, std::any val, float* speed, int64_t* enabled, std::string* pBezier, void* pWindow, AVARDAMAGEPOLICY);
void create(ANIMATEDVARTYPE, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
void create(ANIMATEDVARTYPE, std::any val, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
~CAnimatedVariable();
@@ -128,10 +130,12 @@ public:
case AVARTYPE_COLOR:
return m_cValue != m_cGoal;
default:
std::unreachable();
UNREACHABLE();
}
std::unreachable();
UNREACHABLE();
return false; // just so that the warning is suppressed
}
void warp() {
@@ -149,10 +153,20 @@ public:
break;
}
default:
std::unreachable();
UNREACHABLE();
}
}
void setConfig(SAnimationPropertyConfig* pConfig) {
m_pConfig = pConfig;
}
SAnimationPropertyConfig* getConfig() {
return m_pConfig;
}
int getDurationLeftMs();
private:
Vector2D m_vValue = Vector2D(0,0);
@@ -167,15 +181,12 @@ private:
float m_fBegun = 0;
CColor m_cBegun;
float* m_pSpeed = nullptr;
int64_t* m_pEnabled = nullptr;
// owners
void* m_pWindow = nullptr;
void* m_pWorkspace = nullptr;
void* m_pLayer = nullptr;
std::string* m_pBezier = nullptr;
SAnimationPropertyConfig* m_pConfig = nullptr;
bool m_bDummy = true;

View File

@@ -3,6 +3,7 @@
#include <algorithm>
#include "../Compositor.hpp"
#include <sys/utsname.h>
#include <iomanip>
static const float transforms[][9] = {{
1.0f, 0.0f, 0.0f,
@@ -82,37 +83,42 @@ void wlr_signal_emit_safe(struct wl_signal *signal, void *data) {
}
std::string getFormat(const char *fmt, ...) {
char buf[LOGMESSAGESIZE] = "";
char* outputStr;
int logLen;
char* outputStr = nullptr;
va_list args;
va_start(args, fmt);
logLen = vsnprintf(buf, sizeof buf, fmt, args);
vasprintf(&outputStr, fmt, args);
va_end(args);
if ((long unsigned int)logLen < sizeof buf) {
outputStr = strdup(buf);
} else {
outputStr = (char*)malloc(logLen + 1);
if (!outputStr) {
printf("CRITICAL: Cannot alloc size %d for log! (Out of memory?)", logLen + 1);
return "";
}
va_start(args, fmt);
vsnprintf(outputStr, logLen + 1U, fmt, args);
va_end(args);
}
std::string output = std::string(outputStr);
free(outputStr);
return output;
}
std::string escapeJSONStrings(const std::string& str) {
std::ostringstream oss;
for (auto &c : str) {
switch (c) {
case '"': oss << "\\\""; break;
case '\\': oss << "\\\\"; break;
case '\b': oss << "\\b"; break;
case '\f': oss << "\\f"; break;
case '\n': oss << "\\n"; break;
case '\r': oss << "\\r"; break;
case '\t': oss << "\\t"; break;
default:
if ('\x00' <= c && c <= '\x1f') {
oss << "\\u"
<< std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(c);
} else {
oss << c;
}
}
}
return oss.str();
}
void scaleBox(wlr_box* box, float scale) {
box->width = std::round(box->width * scale);
box->height = std::round(box->height * scale);
@@ -193,7 +199,9 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
}
outName = WORKSPACENAME;
} else {
if (in[0] == 'm') {
if (in[0] == 'm' || in[0] == 'e') {
bool onAllMonitors = in[0] == 'e';
if (!g_pCompositor->m_pLastMonitor) {
Debug::log(ERR, "Relative monitor workspace on monitor null!");
result = INT_MAX;
@@ -234,7 +242,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
}
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(searchID); PWORKSPACE && PWORKSPACE->m_iID != SPECIAL_WORKSPACE_ID) {
if (PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
if (onAllMonitors || PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
currentID = PWORKSPACE->m_iID;
if (remains < 0)

View File

@@ -5,6 +5,7 @@
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, std::string ownerString);
void wlr_signal_emit_safe(struct wl_signal *signal, void *data);
std::string getFormat(const char *fmt, ...); // Basically Debug::log to a string
std::string escapeJSONStrings(const std::string& str);
void scaleBox(wlr_box*, float);
std::string removeBeginEndSpacesTabs(std::string);
bool isNumber(const std::string&, bool allowfloat = false);

166
src/helpers/Monitor.cpp Normal file
View File

@@ -0,0 +1,166 @@
#include "Monitor.hpp"
#include "../Compositor.hpp"
void CMonitor::onConnect(bool noRule) {
// get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name);
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
wlr_output_enable(output, 0);
wlr_output_commit(output);
hyprListener_monitorFrame.removeCallback();
return;
}
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()){
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
}
m_bEnabled = true;
ID = g_pCompositor->getNextAvailableMonitorID();
szName = output->name;
wlr_output_set_scale(output, monitorRule.scale);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms
wlr_output_enable_adaptive_sync(output, 1);
// create it in the arr
vecPosition = monitorRule.offset;
vecSize = monitorRule.resolution;
refreshRate = monitorRule.refreshRate;
wlr_output_enable(output, 1);
// TODO: this doesn't seem to set the X and Y correctly,
// wlr_output_layout_output_coords returns invalid values, I think...
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, monitorRule.offset.x, monitorRule.offset.y);
// set mode, also applies
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %x", output->name, (int)monitorRule.offset.x, (int)monitorRule.offset.y, (int)monitorRule.resolution.x, (int)monitorRule.resolution.y, output);
damage = wlr_output_damage_create(output);
// add a WLR workspace group
if (!pWLRWorkspaceGroupHandle) {
pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
}
wlr_ext_workspace_group_handle_v1_output_enter(pWLRWorkspaceGroupHandle, output);
// Workspace
std::string newDefaultWorkspaceName = "";
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace.c_str());
}
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this);
activeWorkspace = PNEWWORKSPACE->m_iID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
PNEWWORKSPACE->startAnim(true, true, true);
} else {
if (newDefaultWorkspaceName == "")
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();
// We are required to set the name here immediately
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
PNEWWORKSPACE->m_iID = WORKSPACEID;
}
activeWorkspace = PNEWWORKSPACE->m_iID;
scale = monitorRule.scale;
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
PNEWWORKSPACE->setActive(true);
//
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->m_pLastMonitor = this;
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
}
void CMonitor::onDisconnect() {
// Cleanup everything. Move windows back, snap cursor, shit.
CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m.get() != this) {
BACKUPMON = m.get();
break;
}
}
if (!BACKUPMON) {
Debug::log(CRIT, "No monitors! Unplugged last! Exiting.");
g_pCompositor->cleanup();
return;
}
m_bEnabled = false;
hyprListener_monitorFrame.removeCallback();
const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;
// snap cursor
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
// move workspaces
std::deque<CWorkspace*> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID) {
wspToMove.push_back(w.get());
}
}
for (auto& w : wspToMove) {
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
w->startAnim(true, true, true);
}
activeWorkspace = -1;
wlr_output_damage_destroy(damage);
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
wlr_output_enable(output, false);
wlr_output_commit(output);
g_pCompositor->m_vWorkspaces.erase(std::remove_if(g_pCompositor->m_vWorkspaces.begin(), g_pCompositor->m_vWorkspaces.end(), [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; }));
Debug::log(LOG, "Removed monitor %s!", szName.c_str());
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
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; }));
}

View File

@@ -3,10 +3,12 @@
#include "../defines.hpp"
#include <deque>
#include "WLClasses.hpp"
#include <list>
#include <vector>
#include <array>
#include <memory>
struct SMonitor {
class CMonitor {
public:
Vector2D vecPosition = Vector2D(0,0);
Vector2D vecSize = Vector2D(0,0);
Vector2D vecPixelSize = Vector2D(0,0);
@@ -30,6 +32,7 @@ struct SMonitor {
int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
// for the special workspace
@@ -38,7 +41,7 @@ struct SMonitor {
// Double-linked list because we need to have constant mem addresses for signals
// We have to store pointers and use raw new/delete because they might be moved between them
// and I am lazy
std::array<std::list<SLayerSurface*>, 4> m_aLayerSurfaceLists;
std::array<std::vector<std::unique_ptr<SLayerSurface>>, 4> m_aLayerSurfaceLists;
DYNLISTENER(monitorFrame);
DYNLISTENER(monitorDestroy);
@@ -49,9 +52,16 @@ struct SMonitor {
wlr_ext_workspace_group_handle_v1* pWLRWorkspaceGroupHandle = nullptr;
// methods
void onConnect(bool noRule);
void onDisconnect();
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
bool m_bEnabled = false;
// For the list lookup
bool operator==(const SMonitor& rhs) {
bool operator==(const CMonitor& rhs) {
return vecPosition == rhs.vecPosition && vecSize == rhs.vecSize && szName == rhs.szName;
}
};

View File

@@ -21,9 +21,7 @@ void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
}
SSurfaceTreeNode* createTree(wlr_surface* pSurface, CWindow* pWindow) {
SubsurfaceTree::surfaceTreeNodes.push_back(SSurfaceTreeNode());
const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.back();
const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.emplace_back();
PNODE->pSurface = pSurface;
PNODE->pWindowOwner = pWindow;
@@ -128,8 +126,7 @@ void Events::listener_newSubsurfaceNode(void* owner, void* data) {
const auto PSUBSURFACE = (wlr_subsurface*)data;
pNode->childSubsurfaces.push_back(SSubsurface());
const auto PNEWSUBSURFACE = &pNode->childSubsurfaces.back();
const auto PNEWSUBSURFACE = &pNode->childSubsurfaces.emplace_back();
Debug::log(LOG, "Added a new subsurface %x", PSUBSURFACE);
@@ -171,12 +168,14 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
addSurfaceGlobalOffset(PNODE, &lx, &ly);
wlr_box extents = {0};
wlr_surface_get_extends(PNODE->pSurface, &extents);
if (PNODE->pSurface) {
wlr_surface_get_extends(PNODE->pSurface, &extents);
extents.x += lx;
extents.y += ly;
extents.x += lx;
extents.y += ly;
g_pHyprRenderer->damageBox(&extents);
g_pHyprRenderer->damageBox(&extents);
}
SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
subsurface->pChild = nullptr;

View File

@@ -2,6 +2,6 @@
#include "../config/ConfigManager.hpp"
SLayerSurface::SLayerSurface() {
alpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, nullptr, AVARDAMAGE_ENTIRE);
alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE);
alpha.m_pLayer = this;
}

View File

@@ -19,10 +19,12 @@ struct SLayerSurface {
DYNLISTENER(commitLayerSurface);
DYNLISTENER(newPopup);
wlr_box geometry;
wlr_box geometry = {0,0,0,0};
Vector2D position;
zwlr_layer_shell_v1_layer layer;
bool mapped = false;
int monitorID = -1;
std::string szNamespace = "";
@@ -30,6 +32,7 @@ struct SLayerSurface {
CAnimatedVariable alpha;
bool fadingOut = false;
bool readyToDelete = false;
bool noProcess = false;
bool forceBlur = false;
@@ -68,8 +71,8 @@ struct SRenderData {
// for blurring
bool blur = false;
// for windows that animate poorly
bool squishOversized = false;
// only for windows, not popups
bool squishOversized = true;
};
struct SExtensionFindingData {
@@ -140,18 +143,19 @@ struct SConstraint {
}
};
struct SMonitor;
class CMonitor;
struct SXDGPopup {
CWindow* parentWindow = nullptr;
SXDGPopup* parentPopup = nullptr;
wlr_xdg_popup* popup = nullptr;
SMonitor* monitor = nullptr;
CMonitor* monitor = nullptr;
DYNLISTENER(newPopupFromPopupXDG);
DYNLISTENER(destroyPopupXDG);
DYNLISTENER(mapPopupXDG);
DYNLISTENER(unmapPopupXDG);
DYNLISTENER(commitPopupXDG);
double lx;
double ly;
@@ -267,5 +271,5 @@ struct SSwipeGesture {
float avgSpeed = 0;
int speedPoints = 0;
SMonitor* pMonitor = nullptr;
CMonitor* pMonitor = nullptr;
};

View File

@@ -4,9 +4,9 @@
#include "../debug/Log.hpp"
void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener* pListener = wl_container_of(listener, pListener, m_sListener);
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
pListener->emit(data);
pWrap->m_pSelf->emit(data);
}
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {
@@ -14,7 +14,9 @@ CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, v
}
CHyprWLListener::CHyprWLListener() {
; //
m_swWrapper.m_pSelf = this;
m_swWrapper.m_sListener.notify = &handleWrapped;
wl_list_init(&m_swWrapper.m_sListener.link);
}
CHyprWLListener::~CHyprWLListener() {
@@ -22,31 +24,28 @@ CHyprWLListener::~CHyprWLListener() {
}
void CHyprWLListener::removeCallback() {
if (m_bIsConnected) {
Debug::log(LOG, "Callback %x -> %x, %s removed.", m_pCallback, m_pOwner, m_szAuthor.c_str());
wl_list_remove(&m_sListener.link);
if (isConnected()) {
Debug::log(LOG, "Callback %x -> %x, %s removed.", &m_pCallback, &m_pOwner, m_szAuthor.c_str());
wl_list_remove(&m_swWrapper.m_sListener.link);
wl_list_init(&m_swWrapper.m_sListener.link);
}
m_bIsConnected = false;
}
bool CHyprWLListener::isConnected() {
return m_bIsConnected;
return !wl_list_empty(&m_swWrapper.m_sListener.link);
}
void CHyprWLListener::initCallback(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner, std::string author) {
if (m_bIsConnected)
removeCallback();
if (isConnected()) {
Debug::log(ERR, "Tried to connect a listener twice?!");
return;
}
m_pOwner = pOwner;
m_pCallback = callback;
m_szAuthor = author;
m_sListener.notify = &handleWrapped;
m_bIsConnected = true;
addWLSignal(pSignal, &m_sListener, pOwner, m_szAuthor);
addWLSignal(pSignal, &m_swWrapper.m_sListener, pOwner, m_szAuthor);
}
void CHyprWLListener::emit(void* data) {

View File

@@ -9,18 +9,26 @@ public:
CHyprWLListener();
~CHyprWLListener();
CHyprWLListener(const CHyprWLListener&) = delete;
CHyprWLListener(CHyprWLListener&&) = delete;
CHyprWLListener& operator=(const CHyprWLListener&) = delete;
CHyprWLListener& operator=(CHyprWLListener&&) = delete;
void initCallback(wl_signal*, std::function<void(void*, void*)>, void* owner, std::string author = "");
void removeCallback();
bool isConnected();
wl_listener m_sListener;
struct SWrapper {
wl_listener m_sListener;
CHyprWLListener* m_pSelf;
};
void emit(void*);
private:
bool m_bIsConnected = false;
SWrapper m_swWrapper;
void* m_pOwner = nullptr;

View File

@@ -26,9 +26,9 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
}
m_vRenderOffset.m_pWorkspace = this;
m_vRenderOffset.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:workspaces_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces")->intValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces_curve")->strValue, nullptr, AVARDAMAGE_ENTIRE);
m_vRenderOffset.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
m_fAlpha.m_pWorkspace = this;
m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:workspaces_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces")->intValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces_curve")->strValue, nullptr, AVARDAMAGE_ENTIRE);
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
m_fAlpha.setValueAndWarp(255.f);
g_pEventManager->postEvent({"createworkspace", m_szName}, true);
@@ -49,7 +49,7 @@ CWorkspace::~CWorkspace() {
}
void CWorkspace::startAnim(bool in, bool left, bool instant) {
const auto ANIMSTYLE = g_pConfigManager->getString("animations:workspaces_style");
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
if (ANIMSTYLE == "fade") {
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade.

View File

@@ -93,6 +93,7 @@ extern "C" {
#include <wlr/types/wlr_xdg_foreign_v1.h>
#include <wlr/types/wlr_xdg_foreign_v2.h>
#include <wlr/types/wlr_pointer_gestures_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h>
}
#undef class

View File

@@ -23,19 +23,21 @@ void SDwindleNodeData::recalcSizePosRecursive() {
const auto REVERSESPLITRATIO = 2.f - splitRatio;
if (g_pConfigManager->getInt("dwindle:preserve_split") == 0)
splitTop = size.y > size.x;
if (g_pConfigManager->getInt("dwindle:preserve_split") == 0) {
const auto WIDTHMULTIPLIER = g_pConfigManager->getFloat("dwindle:split_width_multiplier");
splitTop = size.y * WIDTHMULTIPLIER > size.x;
}
const auto SPLITSIDE = !splitTop;
if (SPLITSIDE) {
// split sidey
// split left/right
children[0]->position = position;
children[0]->size = Vector2D(size.x / 2.f * splitRatio, size.y);
children[1]->position = Vector2D(position.x + size.x / 2.f * splitRatio, position.y);
children[1]->size = Vector2D(size.x / 2.f * REVERSESPLITRATIO, size.y);
} else {
// split toppy bottomy
// split top/bottom
children[0]->position = position;
children[0]->size = Vector2D(size.x, size.y / 2.f * splitRatio);
children[1]->position = Vector2D(position.x, position.y + size.y / 2.f * splitRatio);
@@ -97,7 +99,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) {
if (pNode->isNode)
return;
SMonitor* PMONITOR = nullptr;
CMonitor* PMONITOR = nullptr;
if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) {
for (auto& m : g_pCompositor->m_vMonitors) {
@@ -215,7 +217,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
} else
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID);
Debug::log(LOG, "OPENINGON: %x, Workspace: %i, Monitor: %i", OPENINGON, PNODE->workspaceID, PMONITOR->ID);
@@ -246,16 +248,19 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
NEWPARENT->pParent = OPENINGON->pParent;
NEWPARENT->isNode = true; // it is a node
const auto WIDTHMULTIPLIER = g_pConfigManager->getFloat("dwindle:split_width_multiplier");
// if cursor over first child, make it first, etc
const auto SIDEBYSIDE = NEWPARENT->size.x / NEWPARENT->size.y > 1.f;
const auto SIDEBYSIDE = NEWPARENT->size.x > NEWPARENT->size.y * WIDTHMULTIPLIER;
NEWPARENT->splitTop = !SIDEBYSIDE;
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
const auto FORCESPLIT = g_pConfigManager->getInt("dwindle:force_split");
if (FORCESPLIT == 0) {
if ((SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y, NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y + NEWPARENT->size.y))
|| (!SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y, NEWPARENT->position.x + NEWPARENT->size.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f))) {
if ((SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / WIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y + NEWPARENT->size.y))
|| (!SIDEBYSIDE && VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / WIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f))) {
// we are hovering over the first node, make PNODE first.
NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[0] = PNODE;
@@ -284,14 +289,16 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
}
// Update the children
if (NEWPARENT->size.x > NEWPARENT->size.y) {
// split sidey
if (NEWPARENT->size.x * WIDTHMULTIPLIER > NEWPARENT->size.y) {
// split left/right
OPENINGON->position = NEWPARENT->position;
OPENINGON->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y);
PNODE->position = Vector2D(NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y);
PNODE->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y);
} else {
// split toppy bottomy
// split top/bottom
OPENINGON->position = NEWPARENT->position;
OPENINGON->size = Vector2D(NEWPARENT->size.x, NEWPARENT->size.y / 2.f);
PNODE->position = Vector2D(NEWPARENT->position.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f);
@@ -541,7 +548,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
g_pEventManager->postEvent(SHyprIPCEvent("fullscreen", std::to_string((int)on)));
g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)});
if (!pWindow->m_bIsFullscreen) {
// if it got its fullscreen disabled, set back its node if it had one
@@ -585,6 +592,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
}
}
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pCompositor->moveWindowToTop(pWindow);
@@ -854,4 +863,17 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) {
std::string CHyprDwindleLayout::getLayoutName() {
return "dwindle";
}
void CHyprDwindleLayout::onEnable() {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->m_bHidden)
continue;
onWindowCreatedTiling(w.get());
}
}
void CHyprDwindleLayout::onDisable() {
m_lDwindleNodesData.clear();
}

View File

@@ -55,6 +55,9 @@ public:
virtual void alterSplitRatioBy(CWindow*, float);
virtual std::string getLayoutName();
virtual void onEnable();
virtual void onDisable();
private:
std::list<SDwindleNodeData> m_lDwindleNodesData;

View File

@@ -32,11 +32,21 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
return;
}
if (desiredGeometry.width <= 0 || desiredGeometry.height <= 0) {
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height);
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.vec().x) / 2.f, PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.vec().y) / 2.f);
if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11) { // XDG windows should be fine. TODO: check for weird atoms?
pWindow->m_bHidden = true;
return;
}
// reject any windows with size <= 5x5
if (pWindow->m_vRealSize.goalv().x <= 5 || pWindow->m_vRealSize.goalv().y <= 5) {
pWindow->m_vRealSize = PMONITOR->vecSize / 2.f;
}
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goalv().x) / 2.f, PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goalv().y) / 2.f);
} else {
// we respect the size.
pWindow->m_vRealSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
@@ -96,6 +106,9 @@ void IHyprLayout::onBeginDragWindow() {
return;
}
DRAGGINGWINDOW->m_vRealPosition.setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
DRAGGINGWINDOW->m_vRealSize.setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
DRAGGINGWINDOW->m_bDraggingTiled = false;
if (!DRAGGINGWINDOW->m_bIsFloating) {
@@ -112,6 +125,9 @@ void IHyprLayout::onBeginDragWindow() {
m_vLastDragXY = m_vBeginDragXY;
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
// shadow to ignore any bound to MAIN_MOD
g_pKeybindManager->shadowKeybinds();
}
void IHyprLayout::onEndDragWindow() {

View File

@@ -16,6 +16,8 @@ enum eFullscreenMode : uint8_t;
interface IHyprLayout {
public:
virtual void onEnable() = 0;
virtual void onDisable() = 0;
/*
Called when a window is created (mapped)

526
src/layout/MasterLayout.cpp Normal file
View File

@@ -0,0 +1,526 @@
#include "MasterLayout.hpp"
#include "../Compositor.hpp"
SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(CWindow* pWindow) {
for (auto& nd : m_lMasterNodesData) {
if (nd.pWindow == pWindow)
return &nd;
}
return nullptr;
}
int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) {
int no = 0;
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == ws)
no++;
}
return no;
}
std::string CHyprMasterLayout::getLayoutName() {
return "Master";
}
SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const int& ws) {
for (auto& n : m_lMasterNodesData) {
if (n.isMaster && n.workspaceID == ws)
return &n;
}
return nullptr;
}
void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
if (pWindow->m_bIsFloating)
return;
static auto *const PNEWTOP = &g_pConfigManager->getConfigValuePtr("master:new_on_top")->intValue;
const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back();
PNODE->workspaceID = pWindow->m_iWorkspaceID;
PNODE->pWindow = pWindow;
static auto *const PNEWISMASTER = &g_pConfigManager->getConfigValuePtr("master:new_is_master")->intValue;
const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID);
float lastSplitPercent = 0.5f;
if (*PNEWISMASTER || WINDOWSONWORKSPACE == 1) {
for (auto& nd : m_lMasterNodesData) {
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
nd.isMaster = false;
lastSplitPercent = nd.percMaster;
break;
}
}
PNODE->isMaster = true;
PNODE->percMaster = lastSplitPercent;
} else {
PNODE->isMaster = false;
}
// recalc
recalculateMonitor(pWindow->m_iMonitorID);
}
void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE)
return;
if (PNODE->isMaster) {
// find new one
for (auto& nd : m_lMasterNodesData) {
if (!nd.isMaster) {
nd.isMaster = true;
break;
}
}
}
m_lMasterNodesData.remove(*PNODE);
recalculateMonitor(pWindow->m_iMonitorID);
}
void CHyprMasterLayout::recalculateMonitor(const int& monid) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
if (!PWORKSPACE)
return;
g_pHyprRenderer->damageMonitor(PMONITOR);
if (PMONITOR->specialWorkspaceOpen) {
calculateWorkspace(SPECIAL_WORKSPACE_ID);
}
if (PWORKSPACE->m_bHasFullscreenWindow) {
if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL)
return;
// massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
SMasterNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = PWORKSPACE->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.position;
PFULLWINDOW->m_vSize = fakeNode.size;
applyNodeDataToWindow(&fakeNode);
return;
}
// calc the WS
calculateWorkspace(PWORKSPACE->m_iID);
}
void CHyprMasterLayout::calculateWorkspace(const int& ws) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(ws);
if (!PWORKSPACE)
return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PMASTERNODE = getMasterNodeOnWorkspace(PWORKSPACE->m_iID);
if (!PMASTERNODE)
return;
if (getNodesOnWorkspace(PWORKSPACE->m_iID) < 2) {
PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
PMASTERNODE->size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
applyNodeDataToWindow(PMASTERNODE);
return;
} else {
PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition;
PMASTERNODE->size = Vector2D((PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
}
const auto SLAVESIZE = 1.f / (getNodesOnWorkspace(PWORKSPACE->m_iID) - 1) * (PMASTERNODE->size.y);
int slavesDone = 0;
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID)
continue;
if (nd == *PMASTERNODE) {
applyNodeDataToWindow(PMASTERNODE);
continue;
}
nd.position = Vector2D(PMASTERNODE->size.x + PMASTERNODE->position.x, slavesDone * SLAVESIZE + PMASTERNODE->position.y);
nd.size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x - PMASTERNODE->size.x, SLAVESIZE);
slavesDone++;
applyNodeDataToWindow(&nd);
}
}
void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
CMonitor* PMONITOR = nullptr;
if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) {
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->specialWorkspaceOpen) {
PMONITOR = m.get();
break;
}
}
} else {
PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID);
}
if (!PMONITOR) {
Debug::log(ERR, "Orphaned Node %x (workspace ID: %i)!!", pNode, pNode->workspaceID);
return;
}
// for gaps outer
const bool DISPLAYLEFT = STICKS(pNode->position.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool DISPLAYRIGHT = STICKS(pNode->position.x + pNode->size.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size");
const auto GAPSIN = g_pConfigManager->getInt("general:gaps_in");
const auto GAPSOUT = g_pConfigManager->getInt("general:gaps_out");
const auto PWINDOW = pNode->pWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)) {
Debug::log(ERR, "Node %x holding invalid window %x!!", pNode, PWINDOW);
return;
}
PWINDOW->m_vSize = pNode->size;
PWINDOW->m_vPosition = pNode->position;
// TODO: special
auto calcPos = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE);
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE);
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN,
DISPLAYTOP ? GAPSOUT : GAPSIN);
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? GAPSOUT : GAPSIN,
DISPLAYBOTTOM ? GAPSOUT : GAPSIN);
calcPos = calcPos + OFFSETTOPLEFT;
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) {
static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue;
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
PWINDOW->m_vRealSize = calcSize * *PSCALEFACTOR;
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize * *PSCALEFACTOR);
} else {
PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos;
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
}
PWINDOW->updateWindowDecos();
}
bool CHyprMasterLayout::isWindowTiled(CWindow* pWindow) {
return getNodeFromWindow(pWindow) != nullptr;
}
void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* pWindow) {
const auto PWINDOW = pWindow ? pWindow : g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).x, (double)20, (double)999999), std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).y, (double)20, (double)999999));
PWINDOW->updateWindowDecos();
return;
}
// get master
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2)
return;
float delta = pixResize.x / PMONITOR->vecSize.x;
PMASTER->percMaster += delta;
std::clamp(PMASTER->percMaster, 0.05f, 0.95f);
recalculateMonitor(PMONITOR->ID);
}
void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) {
if (!g_pCompositor->windowValidMapped(pWindow))
return;
if (on == pWindow->m_bIsFullscreen)
return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow && on) {
// if the window wants to be fullscreen but there already is one,
// ignore the request.
return;
}
// otherwise, accept it.
pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)});
if (!pWindow->m_bIsFullscreen) {
// if it got its fullscreen disabled, set back its node if it had one
const auto PNODE = getNodeFromWindow(pWindow);
if (PNODE)
applyNodeDataToWindow(PNODE);
else {
// get back its' dimensions from position and size
pWindow->m_vRealPosition = pWindow->m_vPosition;
pWindow->m_vRealSize = pWindow->m_vSize;
}
} else {
// if it now got fullscreen, make it fullscreen
PWORKSPACE->m_efFullscreenMode = fullscreenMode;
// save position and size if floating
if (pWindow->m_bIsFloating) {
pWindow->m_vPosition = pWindow->m_vRealPosition.vec();
pWindow->m_vSize = pWindow->m_vRealSize.vec();
}
// apply new pos and size being monitors' box
if (fullscreenMode == FULLSCREEN_FULL) {
pWindow->m_vRealPosition = PMONITOR->vecPosition;
pWindow->m_vRealSize = PMONITOR->vecSize;
} else {
// This is a massive hack.
// We make a fake "only" node and apply
// To keep consistent with the settings without C+P code
SMasterNodeData fakeNode;
fakeNode.pWindow = pWindow;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.position;
pWindow->m_vSize = fakeNode.size;
applyNodeDataToWindow(&fakeNode);
}
}
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
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);
}
void CHyprMasterLayout::recalculateWindow(CWindow* pWindow) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE)
return;
recalculateMonitor(pWindow->m_iMonitorID);
}
SWindowRenderLayoutHints CHyprMasterLayout::requestRenderHints(CWindow* pWindow) {
// window should be valid, insallah
SWindowRenderLayoutHints hints;
return hints; // master doesnt have any hints
}
void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
// windows should be valid, insallah
const auto PNODE = getNodeFromWindow(pWindow);
const auto PNODE2 = getNodeFromWindow(pWindow2);
if (!PNODE2 || !PNODE)
return;
if (PNODE->workspaceID != PNODE2->workspaceID) {
Debug::log(ERR, "Master: Rejecting a swap between workspaces");
return;
}
// massive hack: just swap window pointers, lol
const auto PWINDOW1 = PNODE->pWindow;
PNODE->pWindow = PNODE2->pWindow;
PNODE2->pWindow = PWINDOW1;
recalculateMonitor(PWINDOW1->m_iMonitorID);
}
void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
// window should be valid, insallah
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE)
return;
const auto PMASTER = getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID);
PMASTER->percMaster = std::clamp(PMASTER->percMaster + ratio, 0.05f, 0.95f);
recalculateMonitor(pWindow->m_iMonitorID);
}
std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::string message) {
auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) {
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f;
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y);
};
if (message == "swapwithmaster") {
const auto PWINDOW = header.pWindow;
if (!isWindowTiled(PWINDOW))
return 0;
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
if (!PMASTER || PMASTER->pWindow == PWINDOW)
return 0;
switchWindows(PWINDOW, PMASTER->pWindow);
switchToWindow(PWINDOW);
return 0;
} else if (message == "cyclenext") {
const auto PWINDOW = header.pWindow;
if (!isWindowTiled(PWINDOW))
return 0;
const auto PNODE = getNodeFromWindow(PWINDOW);
if (PNODE->isMaster) {
// focus the first non master
for (auto n : m_lMasterNodesData) {
if (n.pWindow != PWINDOW && n.workspaceID == PWINDOW->m_iWorkspaceID) {
switchToWindow(n.pWindow);
break;
}
}
} else {
// focus next
bool reached = false;
bool found = false;
for (auto n : m_lMasterNodesData) {
if (n.pWindow == PWINDOW) {
reached = true;
continue;
}
if (n.workspaceID == PWINDOW->m_iWorkspaceID && reached) {
switchToWindow(n.pWindow);
found = true;
break;
}
}
if (!found) {
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
if (PMASTER)
switchToWindow(PMASTER->pWindow);
}
}
} else if (message == "cycleprev") {
const auto PWINDOW = header.pWindow;
if (!isWindowTiled(PWINDOW))
return 0;
const auto PNODE = getNodeFromWindow(PWINDOW);
if (PNODE->isMaster) {
// focus the first non master
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->pWindow != PWINDOW && it->workspaceID == PWINDOW->m_iWorkspaceID) {
switchToWindow(it->pWindow);
break;
}
}
} else {
// focus next
bool reached = false;
bool found = false;
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->pWindow == PWINDOW) {
reached = true;
continue;
}
if (it->workspaceID == PWINDOW->m_iWorkspaceID && reached) {
switchToWindow(it->pWindow);
found = true;
break;
}
}
if (!found) {
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
if (PMASTER)
switchToWindow(PMASTER->pWindow);
}
}
}
return 0;
}
void CHyprMasterLayout::onEnable() {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->m_bHidden)
continue;
onWindowCreatedTiling(w.get());
}
}
void CHyprMasterLayout::onDisable() {
m_lMasterNodesData.clear();
}

View File

@@ -0,0 +1,54 @@
#pragma once
#include "IHyprLayout.hpp"
#include <list>
#include <deque>
enum eFullscreenMode : uint8_t;
struct SMasterNodeData {
bool isMaster = false;
float percMaster = 0.5f;
CWindow* pWindow = nullptr;
Vector2D position;
Vector2D size;
int workspaceID = -1;
bool operator==(const SMasterNodeData& rhs) {
return pWindow == rhs.pWindow;
}
};
class CHyprMasterLayout : public IHyprLayout {
public:
virtual void onWindowCreatedTiling(CWindow*);
virtual void onWindowRemovedTiling(CWindow*);
virtual bool isWindowTiled(CWindow*);
virtual void recalculateMonitor(const int&);
virtual void recalculateWindow(CWindow*);
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
virtual void switchWindows(CWindow*, CWindow*);
virtual void alterSplitRatioBy(CWindow*, float);
virtual std::string getLayoutName();
virtual void onEnable();
virtual void onDisable();
private:
std::list<SMasterNodeData> m_lMasterNodesData;
int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SMasterNodeData*);
SMasterNodeData* getNodeFromWindow(CWindow*);
SMasterNodeData* getMasterNodeOnWorkspace(const int&);
void calculateWorkspace(const int&);
friend struct SMasterNodeData;
};

View File

@@ -15,9 +15,19 @@ int main(int argc, char** argv) {
throw std::runtime_error("XDG_RUNTIME_DIR is not set!");
// parse some args
std::string configPath;
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--i-am-really-stupid"))
ignoreSudo = true;
else if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--config")) && argc >= i + 2) {
configPath = std::string(argv[++i]);
Debug::log(LOG, "Using config location %s.", configPath.c_str());
} else {
std::cout << "Hyprland usage: Hyprland [arg [...]].\n\nArguments:\n" <<
"--help -h | Show this help message\n" <<
"--config -c | Specify config file to use\n";
return 1;
}
}
system("mkdir -p /tmp/hypr");
@@ -37,6 +47,7 @@ int main(int argc, char** argv) {
// let's init the compositor.
// it initializes basic Wayland stuff in the constructor.
g_pCompositor = std::make_unique<CCompositor>();
g_pCompositor->explicitConfigPath = configPath;
Debug::log(LOG, "Hyprland init finished.");
@@ -46,7 +57,7 @@ int main(int argc, char** argv) {
// If we are here it means we got yote.
Debug::log(LOG, "Hyprland reached the end.");
g_pCompositor->cleanupExit();
g_pCompositor->cleanup();
return EXIT_SUCCESS;
}

View File

@@ -28,13 +28,10 @@ void CAnimationManager::tick() {
if (!*PANIMENABLED)
animationsDisabled = true;
static auto *const PANIMSPEED = &g_pConfigManager->getConfigValuePtr("animations:speed")->floatValue;
static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto *const BEZIERSTR = &g_pConfigManager->getConfigValuePtr("animations:curve")->strValue;
static auto *const PSHADOWSENABLED = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
auto DEFAULTBEZIER = m_mBezierCurves.find(*BEZIERSTR);
if (DEFAULTBEZIER == m_mBezierCurves.end())
DEFAULTBEZIER = m_mBezierCurves.find("default");
const auto DEFAULTBEZIER = m_mBezierCurves.find("default");
for (auto& av : m_lAnimatedVariables) {
@@ -42,8 +39,13 @@ void CAnimationManager::tick() {
if (!av->isBeingAnimated())
continue;
if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) {
av->warp();
continue;
}
// get speed
const auto SPEED = *av->m_pSpeed == 0 ? *PANIMSPEED : *av->m_pSpeed;
const auto SPEED = av->m_pConfig->pValues->internalSpeed;
// get the spent % (0 - 1)
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - av->animationBegin).count();
@@ -53,7 +55,7 @@ void CAnimationManager::tick() {
const auto PWINDOW = (CWindow*)av->m_pWindow;
const auto PWORKSPACE = (CWorkspace*)av->m_pWorkspace;
const auto PLAYER = (SLayerSurface*)av->m_pLayer;
SMonitor* PMONITOR = nullptr;
CMonitor* PMONITOR = nullptr;
wlr_box WLRBOXPREV = {0,0,0,0};
if (PWINDOW) {
@@ -73,7 +75,7 @@ void CAnimationManager::tick() {
switch (av->m_eVarType) {
case AVARTYPE_FLOAT: {
// for disabled anims just warp
if (*av->m_pEnabled == 0 || animationsDisabled) {
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp();
break;
}
@@ -84,7 +86,7 @@ void CAnimationManager::tick() {
}
const auto DELTA = av->m_fGoal - av->m_fBegun;
const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier);
const auto BEZIER = m_mBezierCurves.find(av->m_pConfig->pValues->internalBezier);
if (BEZIER != m_mBezierCurves.end())
av->m_fValue = av->m_fBegun + BEZIER->second.getYForPoint(SPENT) * DELTA;
@@ -94,7 +96,7 @@ void CAnimationManager::tick() {
}
case AVARTYPE_VECTOR: {
// for disabled anims just warp
if (*av->m_pEnabled == 0 || animationsDisabled) {
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp();
break;
}
@@ -105,7 +107,7 @@ void CAnimationManager::tick() {
}
const auto DELTA = av->m_vGoal - av->m_vBegun;
const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier);
const auto BEZIER = m_mBezierCurves.find(av->m_pConfig->pValues->internalBezier);
if (BEZIER != m_mBezierCurves.end())
av->m_vValue = av->m_vBegun + DELTA * BEZIER->second.getYForPoint(SPENT);
@@ -115,7 +117,7 @@ void CAnimationManager::tick() {
}
case AVARTYPE_COLOR: {
// for disabled anims just warp
if (*av->m_pEnabled == 0 || animationsDisabled) {
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp();
break;
}
@@ -126,7 +128,7 @@ void CAnimationManager::tick() {
}
const auto DELTA = av->m_cGoal - av->m_cBegun;
const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier);
const auto BEZIER = m_mBezierCurves.find(av->m_pConfig->pValues->internalBezier);
if (BEZIER != m_mBezierCurves.end())
av->m_cValue = av->m_cBegun + DELTA * BEZIER->second.getYForPoint(SPENT);
@@ -181,6 +183,35 @@ void CAnimationManager::tick() {
g_pHyprRenderer->damageBox(WLRBOXNEW.x + WLRBOXNEW.width - ROUNDINGSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, WLRBOXNEW.height + 2 * BORDERSIZE); // right
g_pHyprRenderer->damageBox(WLRBOXNEW.x, WLRBOXNEW.y + WLRBOXNEW.height - ROUNDINGSIZE, WLRBOXNEW.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // bottom
break;
} case AVARDAMAGE_SHADOW: {
RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!");
static auto* const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW);
if (PDECO) {
const auto EXTENTS = PDECO->getWindowDecorationExtents();
wlr_box dmg = {PWINDOW->m_vRealPosition.vec().x + EXTENTS.topLeft.x, PWINDOW->m_vRealPosition.vec().y + EXTENTS.topLeft.y,
PWINDOW->m_vRealSize.vec().x + EXTENTS.topLeft.x + EXTENTS.bottomRight.x, PWINDOW->m_vRealSize.vec().y + EXTENTS.topLeft.y + EXTENTS.bottomRight.y};
if (!*PSHADOWIGNOREWINDOW) {
// easy, damage the entire box
g_pHyprRenderer->damageBox(&dmg);
} else {
pixman_region32_t rg;
pixman_region32_init_rect(&rg, dmg.x, dmg.y, dmg.width, dmg.height);
pixman_region32_t wb;
pixman_region32_init_rect(&wb, PWINDOW->m_vRealPosition.vec().x, PWINDOW->m_vRealPosition.vec().y, PWINDOW->m_vRealSize.vec().x, PWINDOW->m_vRealSize.vec().y);
pixman_region32_subtract(&rg, &rg, &wb);
g_pHyprRenderer->damageRegion(&rg);
pixman_region32_fini(&rg);
pixman_region32_fini(&wb);
}
}
break;
}
default: {
@@ -195,7 +226,7 @@ void CAnimationManager::tick() {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
// manually schedule a frame
wlr_output_schedule_frame(PMONITOR->output);
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
}
}
@@ -299,7 +330,17 @@ void CAnimationManager::animationSlide(CWindow* pWindow, std::string force, bool
}
void CAnimationManager::onWindowPostCreateClose(CWindow* pWindow, bool close) {
auto ANIMSTYLE = g_pConfigManager->getString("animations:windows_style");
if (!close) {
pWindow->m_vRealPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsIn");
pWindow->m_vRealSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsIn");
pWindow->m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeIn");
} else {
pWindow->m_vRealPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsOut");
pWindow->m_vRealSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsOut");
pWindow->m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeOut");
}
auto ANIMSTYLE = pWindow->m_vRealPosition.m_pConfig->pValues->internalStyle;
transform(ANIMSTYLE.begin(), ANIMSTYLE.end(), ANIMSTYLE.begin(), ::tolower);
// if the window is not being animated, that means the layout set a fixed size for it, don't animate.

View File

@@ -33,10 +33,18 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["focuswindowbyclass"] = focusWindow;
m_mDispatchers["focuswindow"] = focusWindow;
m_mDispatchers["submap"] = setSubmap;
m_mDispatchers["pass"] = pass;
m_mDispatchers["layoutmsg"] = layoutmsg;
m_mDispatchers["toggleopaque"] = toggleOpaque;
m_mDispatchers["dpms"] = dpms;
m_tScrollTimer.reset();
}
void CKeybindManager::addKeybind(SKeybind kb) {
m_lKeybinds.push_back(kb);
m_pActiveKeybind = nullptr;
}
void CKeybindManager::removeKeybind(uint32_t mod, const std::string& key) {
@@ -58,6 +66,8 @@ void CKeybindManager::removeKeybind(uint32_t mod, const std::string& key) {
break;
}
}
m_pActiveKeybind = nullptr;
}
uint32_t CKeybindManager::stringToModMask(std::string mods) {
@@ -82,26 +92,144 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
return modMask;
}
bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t& key, const int& keycode) {
bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
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 auto MODS = g_pInputManager->accumulateModsFromAllKBs();
m_uTimeLastMs = e->time_msec;
m_uLastCode = KEYCODE;
bool found = false;
if (e->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
// clean repeat
if (m_pActiveKeybindEventSource) {
wl_event_source_remove(m_pActiveKeybindEventSource);
m_pActiveKeybindEventSource = nullptr;
m_pActiveKeybind = nullptr;
}
m_dPressedKeycodes.push_back(KEYCODE);
m_dPressedKeysyms.push_back(keysym);
found = g_pKeybindManager->handleKeybinds(MODS, "", keysym, 0, true, e->time_msec) || found;
found = g_pKeybindManager->handleKeybinds(MODS, "", 0, KEYCODE, true, e->time_msec) || found;
if (found)
shadowKeybinds(keysym, KEYCODE);
} else if (e->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
// clean repeat
if (m_pActiveKeybindEventSource) {
wl_event_source_remove(m_pActiveKeybindEventSource);
m_pActiveKeybindEventSource = nullptr;
m_pActiveKeybind = nullptr;
}
m_dPressedKeycodes.erase(std::remove(m_dPressedKeycodes.begin(), m_dPressedKeycodes.end(), KEYCODE));
m_dPressedKeysyms.erase(std::remove(m_dPressedKeysyms.begin(), m_dPressedKeysyms.end(), keysym));
found = g_pKeybindManager->handleKeybinds(MODS, "", keysym, 0, false, e->time_msec) || found;
found = g_pKeybindManager->handleKeybinds(MODS, "", 0, KEYCODE, false, e->time_msec) || found;
shadowKeybinds();
}
return !found;
}
bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
static auto *const PDELAY = &g_pConfigManager->getConfigValuePtr("binds:scroll_event_delay")->intValue;
if (m_tScrollTimer.getMillis() < *PDELAY) {
m_tScrollTimer.reset();
return true; // timer hasn't passed yet!
}
m_tScrollTimer.reset();
bool found = false;
if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_VERTICAL) {
if (e->delta < 0) {
found = g_pKeybindManager->handleKeybinds(MODS, "mouse_down", 0, 0, true, 0);
} else {
found = g_pKeybindManager->handleKeybinds(MODS, "mouse_up", 0, 0, true, 0);
}
if (found)
shadowKeybinds();
}
return !found;
}
bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
bool found = false;
if (handleInternalKeybinds(key))
if (e->state == WLR_BUTTON_PRESSED) {
found = g_pKeybindManager->handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, true, 0);
if (found)
shadowKeybinds();
} else {
found = g_pKeybindManager->handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, false, 0);
shadowKeybinds();
}
return !found;
}
int repeatKeyHandler(void* data) {
SKeybind** ppActiveKeybind = (SKeybind**)data;
if (!*ppActiveKeybind)
return 0;
const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find((*ppActiveKeybind)->handler);
Debug::log(LOG, "Keybind repeat triggered, calling dispatcher.");
DISPATCHER->second((*ppActiveKeybind)->arg);
wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pInputManager->m_pActiveKeyboard->repeatRate);
return 0;
}
bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string& key, const xkb_keysym_t& keysym, const int& keycode, bool pressed, uint32_t time) {
bool found = false;
if (handleInternalKeybinds(keysym))
return true;
if (g_pCompositor->m_sSeat.exclusiveClient)
Debug::log(LOG, "Keybind handling only locked (inhibitor)");
if (pressed && m_kHeldBack) {
// release the held back event
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, time, m_kHeldBack, WL_KEYBOARD_KEY_STATE_PRESSED);
m_kHeldBack = 0;
}
for (auto& k : m_lKeybinds) {
if (modmask != k.modmask || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap)
if (modmask != k.modmask || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap || (!pressed && !k.release) || k.shadowed)
continue;
if (k.keycode != -1) {
if (!key.empty()) {
if (key != k.key)
continue;
} else if (k.keycode != -1) {
if (keycode != k.keycode)
continue;
} else {
if (key == 0)
if (keysym == 0)
continue; // this is a keycode check run
// oMg such performance hit!!11!
@@ -110,10 +238,16 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t
const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY);
// small TODO: fix 0-9 keys and other modified ones with shift
if (key != KBKEY && key != KBKEYUPPER)
if (keysym != KBKEY && keysym != KBKEYUPPER)
continue;
}
if (pressed && k.release) {
// suppress down event
m_kHeldBack = keysym;
return true;
}
const auto DISPATCHER = m_mDispatchers.find(k.handler);
// Should never happen, as we check in the ConfigManager, but oh well
@@ -121,16 +255,61 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t
Debug::log(ERR, "Inavlid handler in a keybind! (handler %s does not exist)", k.handler.c_str());
} else {
// call the dispatcher
Debug::log(LOG, "Keybind triggered, calling dispatcher (%d, %d)", modmask, key);
Debug::log(LOG, "Keybind triggered, calling dispatcher (%d, %s, %d)", modmask, key.c_str(), keysym);
DISPATCHER->second(k.arg);
}
if (k.repeat) {
m_pActiveKeybind = &k;
m_pActiveKeybindEventSource = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, repeatKeyHandler, &m_pActiveKeybind);
const auto PACTIVEKEEB = g_pInputManager->m_pActiveKeyboard;
wl_event_source_timer_update(m_pActiveKeybindEventSource, PACTIVEKEEB->repeatDelay);
}
found = true;
}
return found;
}
void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const int& doesntHaveCode) {
// shadow disables keybinds after one has been triggered
for (auto& k : m_lKeybinds) {
bool shadow = false;
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY);
for (auto& pk : m_dPressedKeysyms) {
if ((pk == KBKEY || pk == KBKEYUPPER)) {
shadow = true;
if (pk == doesntHave && doesntHave != 0) {
shadow = false;
break;
}
}
}
for (auto& pk : m_dPressedKeycodes) {
if (pk == k.keycode) {
shadow = true;
if (pk == doesntHaveCode && doesntHaveCode != 0 && doesntHaveCode != -1) {
shadow = false;
break;
}
}
}
k.shadowed = shadow;
}
}
bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
// Handles the CTRL+ALT+FX TTY keybinds
if (!(keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12))
@@ -140,11 +319,11 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
if (PSESSION) {
const int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
wlr_session_change_vt(PSESSION, TTY);
g_pCompositor->m_bSessionActive = false;
for (auto& m : g_pCompositor->m_vMonitors) {
g_pHyprOpenGL->destroyMonitorResources(m.get()); // mark resources as unusable anymore
m->noFrameSchedule = true;
m->framesToSkip = 2;
m->framesToSkip = 1;
}
Debug::log(LOG, "Switched to VT %i, destroyed all render data, frames to skip for each: 2", TTY);
@@ -230,7 +409,7 @@ void CKeybindManager::killActive(std::string args) {
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_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // post an activewindow event to empty, as we are currently unfocused
}
g_pCompositor->focusWindow(g_pCompositor->windowFromCursor());
@@ -325,7 +504,7 @@ void CKeybindManager::changeworkspace(std::string args) {
// start anim on new workspace
PWORKSPACETOCHANGETO->startAnim(true, ANIMTOLEFT);
g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACETOCHANGETO->m_szName));
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PWORKSPACETOCHANGETO->m_szName});
}
// If the monitor is not the one our cursor's at, warp to it.
@@ -398,7 +577,7 @@ void CKeybindManager::changeworkspace(std::string args) {
g_pInputManager->refocus();
// Event
g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACE->m_szName));
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PWORKSPACE->m_szName});
Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo);
}
@@ -429,6 +608,9 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
return;
}
auto PSAVEDSIZE = PWINDOW->m_vRealSize.vec();
auto PSAVEDPOS = PWINDOW->m_vRealPosition.vec();
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
g_pKeybindManager->changeworkspace(args);
@@ -456,20 +638,21 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
PWORKSPACE->m_bHasFullscreenWindow = false;
}
if (PWINDOW->m_bIsFullscreen) {
PWINDOW->m_bIsFullscreen = false;
PSAVEDPOS = PSAVEDPOS + Vector2D(10, 10);
PSAVEDSIZE = PSAVEDSIZE - Vector2D(20, 20);
}
// Hack: So that the layout doesnt find our window at the cursor
PWINDOW->m_vPosition = Vector2D(-42069, -42069);
// Save the real position and size because the layout might set its own
const auto PSAVEDSIZE = PWINDOW->m_vRealSize.vec();
const auto PSAVEDPOS = PWINDOW->m_vRealPosition.vec();
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
// and restore it
PWINDOW->m_vRealPosition.setValue(PSAVEDPOS);
PWINDOW->m_vRealSize.setValue(PSAVEDSIZE);
// and restore it
if (PWINDOW->m_bIsFloating) {
PWINDOW->m_vRealPosition.setValue(PWINDOW->m_vRealPosition.vec() - g_pCompositor->getMonitorFromID(OLDWORKSPACE->m_iMonitorID)->vecPosition);
PWINDOW->m_vRealPosition.setValue(PWINDOW->m_vRealPosition.vec() + g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID)->vecPosition);
PWINDOW->m_vRealSize.setValue(PSAVEDSIZE);
PWINDOW->m_vRealPosition.setValueAndWarp(PSAVEDPOS - g_pCompositor->getMonitorFromID(OLDWORKSPACE->m_iMonitorID)->vecPosition + g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID)->vecPosition);
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
}
@@ -812,12 +995,11 @@ void CKeybindManager::workspaceOpt(std::string args) {
}
void CKeybindManager::exitHyprland(std::string argz) {
g_pCompositor->cleanupExit();
exit(0);
g_pCompositor->cleanup();
}
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
SMonitor* PMONITOR = nullptr;
CMonitor* PMONITOR = nullptr;
try {
if (!isNumber(args) && !isDirection(args)) {
@@ -830,6 +1012,9 @@ void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
return;
}
if (!PMONITOR)
return;
// get the current workspace
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
@@ -846,7 +1031,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
std::string workspace = args.substr(0, args.find_first_of(' '));
std::string monitor = args.substr(args.find_first_of(' ') + 1);
SMonitor* PMONITOR = nullptr;
CMonitor* PMONITOR = nullptr;
try {
if (!isNumber(monitor) && !isDirection(monitor)) {
@@ -1048,6 +1233,11 @@ void CKeybindManager::circleNext(std::string arg) {
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow)
return;
if (arg == "last" || arg == "l" || arg == "prev" || arg == "p")
g_pCompositor->focusWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow));
else
@@ -1059,40 +1249,20 @@ void CKeybindManager::circleNext(std::string arg) {
}
void CKeybindManager::focusWindow(std::string regexp) {
bool titleRegex = false;
std::regex regexCheck(regexp);
if (regexp.find("title:") == 0) {
titleRegex = true;
regexCheck = std::regex(regexp.substr(6));
}
const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp);
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_bHidden)
continue;
if (!PWINDOW)
return;
if (titleRegex) {
const auto windowTitle = g_pXWaylandManager->getTitle(w.get());
if (!std::regex_search(windowTitle, regexCheck))
continue;
}
else {
const auto windowClass = g_pXWaylandManager->getAppIDClass(w.get());
if (!std::regex_search(windowClass, regexCheck))
continue;
}
Debug::log(LOG, "Focusing to window name: %s", PWINDOW->m_szTitle.c_str());
Debug::log(LOG, "Focusing to window name: %s", w->m_szTitle.c_str());
changeworkspace("[internal]" + std::to_string(PWINDOW->m_iWorkspaceID));
changeworkspace("[internal]" + std::to_string(w->m_iWorkspaceID));
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->focusWindow(w.get());
const auto MIDPOINT = PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f;
const auto MIDPOINT = w->m_vRealPosition.goalv() + w->m_vRealSize.goalv() / 2.f;
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, MIDPOINT.x, MIDPOINT.y);
break;
}
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, MIDPOINT.x, MIDPOINT.y);
}
void CKeybindManager::setSubmap(std::string submap) {
@@ -1112,3 +1282,64 @@ void CKeybindManager::setSubmap(std::string submap) {
Debug::log(ERR, "Cannot set submap %s, submap doesn't exist (wasn't registered!)", submap.c_str());
}
void CKeybindManager::pass(std::string regexp) {
// find the first window passing the regex
const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp);
if (!PWINDOW) {
Debug::log(ERR, "pass: window not found");
return;
}
const auto PLASTSRF = g_pCompositor->m_pLastFocus;
const auto KEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat);
if (!KEYBOARD){
Debug::log(ERR, "No kb in pass?");
return;
}
// 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_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_enter(g_pCompositor->m_sSeat.seat, PLASTSRF, KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers);
}
void CKeybindManager::layoutmsg(std::string msg) {
SLayoutMessageHeader hd = {g_pCompositor->m_pLastWindow};
g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg);
}
void CKeybindManager::toggleOpaque(std::string unused) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
PWINDOW->m_sAdditionalConfigData.forceOpaque = !PWINDOW->m_sAdditionalConfigData.forceOpaque;
g_pHyprRenderer->damageWindow(PWINDOW);
}
void CKeybindManager::dpms(std::string arg) {
bool enable = arg == "on";
for (auto& m : g_pCompositor->m_vMonitors) {
wlr_output_enable(m->output, enable);
if (!wlr_output_commit(m->output)) {
Debug::log(ERR, "Couldn't commit output %s", m->szName.c_str());
}
if (enable)
g_pHyprRenderer->damageMonitor(m.get());
}
g_pCompositor->m_bDPMSStateON = enable;
}

View File

@@ -6,6 +6,8 @@
#include <unordered_map>
#include <functional>
class CInputManager;
struct SKeybind {
std::string key = "";
int keycode = -1;
@@ -14,25 +16,56 @@ struct SKeybind {
std::string arg = "";
bool locked = false;
std::string submap = "";
bool release = false;
bool repeat = false;
// DO NOT INITIALIZE
bool shadowed = false;
};
enum eFocusWindowMode {
MODE_CLASS_REGEX = 0,
MODE_TITLE_REGEX,
MODE_ADDRESS,
MODE_PID
};
class CKeybindManager {
public:
CKeybindManager();
bool handleKeybinds(const uint32_t&, const xkb_keysym_t&, const int&);
bool onKeyEvent(wlr_keyboard_key_event*, SKeyboard*);
bool onAxisEvent(wlr_pointer_axis_event*);
bool onMouseEvent(wlr_pointer_button_event*);
void addKeybind(SKeybind);
void removeKeybind(uint32_t, const std::string&);
uint32_t stringToModMask(std::string);
void clearKeybinds();
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const int& doesntHaveCode = 0);
std::unordered_map<std::string, std::function<void(std::string)>> m_mDispatchers;
wl_event_source* m_pActiveKeybindEventSource = nullptr;
private:
std::list<SKeybind> m_lKeybinds;
std::deque<xkb_keysym_t> m_dPressedKeysyms;
std::deque<int> m_dPressedKeycodes;
inline static std::string m_szCurrentSelectedSubmap = "";
xkb_keysym_t m_kHeldBack = 0;
SKeybind* m_pActiveKeybind = nullptr;
uint32_t m_uTimeLastMs = 0;
uint32_t m_uLastCode = 0;
CTimer m_tScrollTimer;
bool handleKeybinds(const uint32_t&, const std::string&, const xkb_keysym_t&, const int&, bool, uint32_t);
bool handleInternalKeybinds(xkb_keysym_t);
bool handleVT(xkb_keysym_t);
@@ -64,8 +97,13 @@ private:
static void circleNext(std::string);
static void focusWindow(std::string);
static void setSubmap(std::string);
static void pass(std::string);
static void layoutmsg(std::string);
static void toggleOpaque(std::string);
static void dpms(std::string);
friend class CCompositor;
friend class CInputManager;
};
inline std::unique_ptr<CKeybindManager> g_pKeybindManager;
inline std::unique_ptr<CKeybindManager> g_pKeybindManager;

View File

@@ -4,8 +4,28 @@ IHyprLayout* CLayoutManager::getCurrentLayout() {
switch (m_iCurrentLayoutID) {
case DWINDLE:
return &m_cDwindleLayout;
case MASTER:
return &m_cMasterLayout;
}
// fallback
return &m_cDwindleLayout;
}
void CLayoutManager::switchToLayout(std::string layout) {
if (layout == "dwindle") {
if (m_iCurrentLayoutID != DWINDLE) {
getCurrentLayout()->onDisable();
m_iCurrentLayoutID = DWINDLE;
getCurrentLayout()->onEnable();
}
} else if (layout == "master") {
if (m_iCurrentLayoutID != MASTER) {
getCurrentLayout()->onDisable();
m_iCurrentLayoutID = MASTER;
getCurrentLayout()->onEnable();
}
} else {
Debug::log(ERR, "Unknown layout %s!", layout.c_str());
}
}

View File

@@ -1,20 +1,25 @@
#pragma once
#include "../layout/DwindleLayout.hpp"
#include "../layout/MasterLayout.hpp"
class CLayoutManager {
public:
IHyprLayout* getCurrentLayout();
void switchToLayout(std::string);
private:
enum HYPRLAYOUTS {
DWINDLE = 0,
MASTER
};
HYPRLAYOUTS m_iCurrentLayoutID = DWINDLE;
CHyprDwindleLayout m_cDwindleLayout;
CHyprMasterLayout m_cMasterLayout;
};
inline std::unique_ptr<CLayoutManager> g_pLayoutManager;

View File

@@ -1,34 +1,31 @@
#include "ThreadManager.hpp"
#include "../debug/HyprCtl.hpp"
CThreadManager::CThreadManager() {
m_tMainThread = new std::thread([&]() {
// Call the handle method.
this->handle();
});
m_tMainThread->detach(); // detach and continue.
}
CThreadManager::~CThreadManager() {
//
}
#include "../Compositor.hpp"
int slowUpdate = 0;
void CThreadManager::handle() {
int handleTimer(void* data) {
const auto PTM = (CThreadManager*)data;
g_pConfigManager->tick();
wl_event_source_timer_update(PTM->m_esConfigTimer, 1000);
return 0;
}
CThreadManager::CThreadManager() {
g_pConfigManager->init();
HyprCtl::startHyprCtlSocket();
while (3.1415f) {
slowUpdate++;
if (slowUpdate >= g_pConfigManager->getInt("general:max_fps")){
g_pConfigManager->tick();
slowUpdate = 0;
}
g_pCompositor->startHyprCtlTick();
std::this_thread::sleep_for(std::chrono::microseconds(1000000 / g_pConfigManager->getInt("general:max_fps")));
}
m_esConfigTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleTimer, this);
wl_event_source_timer_update(m_esConfigTimer, 1000);
}
CThreadManager::~CThreadManager() {
//
}

View File

@@ -9,11 +9,9 @@ public:
CThreadManager();
~CThreadManager();
private:
wl_event_source* m_esConfigTimer;
void handle();
std::thread* m_tMainThread;
private:
};
inline std::unique_ptr<CThreadManager> g_pThreadManager;

View File

@@ -121,6 +121,13 @@ void CHyprXWaylandManager::sendCloseWindow(CWindow* pWindow) {
}
void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, const Vector2D& size) {
if ((pWindow->m_vReportedSize == size && pWindow->m_vRealPosition.vec() == pWindow->m_vReportedPosition) || (pWindow->m_vReportedSize == size && !pWindow->m_bIsX11))
return;
pWindow->m_vReportedPosition = pWindow->m_vRealPosition.vec();
pWindow->m_vReportedSize = size;
if (pWindow->m_bIsX11)
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, size.x, size.y);
else

View File

@@ -29,6 +29,7 @@ void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) {
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
static auto* const PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue;
if (!g_pCompositor->m_bReadyToProcess)
return;
@@ -41,6 +42,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (g_pCompositor->m_sSeat.mouse->virt)
return; // don't refocus on virt
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) {
// enable dpms
g_pKeybindManager->dpms("on");
}
Vector2D mouseCoords = getMouseCoordsInternal();
const auto MOUSECOORDSFLOORED = mouseCoords.floor();
@@ -117,7 +123,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
ACTIVEWORKSPACE->setActive(true);
// event
g_pEventManager->postEvent(SHyprIPCEvent("activemon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName));
g_pEventManager->postEvent(SHyprIPCEvent{"activemon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName});
}
Vector2D surfaceCoords;
@@ -169,11 +175,17 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
}
} else {
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen))
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
}
} else
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (!pFoundWindow && refocus)
pFoundWindow = g_pCompositor->getFirstWindowOnWorkspace(PWORKSPACE->m_iID);
if (pFoundWindow) {
if (!pFoundWindow->m_bIsX11) {
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
@@ -230,6 +242,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
} else if (*PFOLLOWMOUSE == 2) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
if (pFoundWindow == g_pCompositor->m_pLastWindow && foundSurface != g_pCompositor->m_pLastFocus) {
// we changed the subsurface
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
return; // don't enter any new surfaces
} else {
@@ -314,6 +332,13 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
return;
}
// notify the keybind manager
static auto *const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue;
const auto PASS = g_pKeybindManager->onMouseEvent(e);
if (!PASS && !*PPASSMOUSE)
return;
switch (e->state) {
case WLR_BUTTON_PRESSED:
if (!g_pCompositor->m_sSeat.mouse->currentConstraint)
@@ -372,6 +397,16 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
m_ecbClickBehavior = CLICKMODE_DEFAULT;
}
void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
bool passEvent = g_pKeybindManager->onAxisEvent(e);
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
if (passEvent) {
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, e->delta, e->delta_discrete, e->source);
}
}
Vector2D CInputManager::getMouseCoordsInternal() {
return Vector2D(g_pCompositor->m_sWLRCursor->x, g_pCompositor->m_sWLRCursor->y);
}
@@ -408,23 +443,28 @@ void CInputManager::setKeyboardLayout() {
}
void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(pKeyboard->name);
auto devname = pKeyboard->name;
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
Debug::log(LOG, "ApplyConfigToKeyboard for \"%s\", hasconfig: %i", pKeyboard->name.c_str(), (int)HASCONFIG);
ASSERT(pKeyboard);
if (!wlr_keyboard_from_input_device(pKeyboard->keyboard))
return;
const auto REPEATRATE = HASCONFIG ? g_pConfigManager->getDeviceInt(pKeyboard->name, "repeat_rate") : g_pConfigManager->getInt("input:repeat_rate");
const auto REPEATDELAY = HASCONFIG ? g_pConfigManager->getDeviceInt(pKeyboard->name, "repeat_delay") : g_pConfigManager->getInt("input:repeat_delay");
const auto REPEATRATE = HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "repeat_rate") : g_pConfigManager->getInt("input:repeat_rate");
const auto REPEATDELAY = HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "repeat_delay") : g_pConfigManager->getInt("input:repeat_delay");
const auto NUMLOCKON = HASCONFIG ? g_pConfigManager->getDeviceInt(pKeyboard->name, "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 RULES = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_rules") : g_pConfigManager->getString("input:kb_rules");
const auto MODEL = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_model") : g_pConfigManager->getString("input:kb_model");
const auto LAYOUT = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_layout") : g_pConfigManager->getString("input:kb_layout");
const auto VARIANT = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_variant") : g_pConfigManager->getString("input:kb_variant");
const auto OPTIONS = HASCONFIG ? g_pConfigManager->getDeviceString(pKeyboard->name, "kb_options") : g_pConfigManager->getString("input:kb_options");
const auto RULES = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_rules") : g_pConfigManager->getString("input:kb_rules");
const auto MODEL = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_model") : g_pConfigManager->getString("input:kb_model");
const auto LAYOUT = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_layout") : g_pConfigManager->getString("input:kb_layout");
const auto VARIANT = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_variant") : g_pConfigManager->getString("input:kb_variant");
const auto OPTIONS = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_options") : g_pConfigManager->getString("input:kb_options");
try {
if (NUMLOCKON == pKeyboard->numlockOn && REPEATDELAY == pKeyboard->repeatDelay && REPEATRATE == pKeyboard->repeatRate && RULES != "" && RULES == pKeyboard->currentRules.rules && MODEL == pKeyboard->currentRules.model && LAYOUT == pKeyboard->currentRules.layout && VARIANT == pKeyboard->currentRules.variant && OPTIONS == pKeyboard->currentRules.options) {
@@ -513,47 +553,14 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
Debug::log(ERR, "Mouse had no name???"); // logic error
}
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(PMOUSE->name);
if (wlr_input_device_is_libinput(mouse)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(mouse);
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "clickfinger_behavior") : g_pConfigManager->getInt("input:touchpad:clickfinger_behavior")) == 0) // toggle software buttons or clickfinger
libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
else
libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
if (libinput_device_config_middle_emulation_is_available(LIBINPUTDEV)) { // middleclick on r+l mouse button pressed
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "middle_button_emulation") : g_pConfigManager->getInt("input:touchpad:middle_button_emulation")) == 1)
libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED);
else
libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED);
}
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "drag_lock") : g_pConfigManager->getInt("input:touchpad:drag_lock")) == 0)
libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_DISABLED);
else
libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_ENABLED);
if (libinput_device_config_tap_get_finger_count(LIBINPUTDEV)) // this is for tapping (like on a laptop)
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "tap-to-click") : g_pConfigManager->getInt("input:touchpad:tap-to-click")) == 1)
libinput_device_config_tap_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_ENABLED);
if (libinput_device_config_scroll_has_natural_scroll(LIBINPUTDEV)) {
double w = 0, h = 0;
if (libinput_device_has_capability(LIBINPUTDEV, LIBINPUT_DEVICE_CAP_POINTER) && libinput_device_get_size(LIBINPUTDEV, &w, &h) == 0) // pointer with size is a touchpad
libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, (HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "natural_scroll") : g_pConfigManager->getInt("input:touchpad:natural_scroll")));
else
libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, (HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "natural_scroll") : g_pConfigManager->getInt("input:natural_scroll")));
}
if (libinput_device_config_dwt_is_available(LIBINPUTDEV)) {
const auto DWT = static_cast<enum libinput_config_dwt_state>((HASCONFIG ? g_pConfigManager->getDeviceInt(PMOUSE->name, "disable_while_typing") : g_pConfigManager->getInt("input:touchpad:disable_while_typing")) != 0);
libinput_device_config_dwt_set_enabled(LIBINPUTDEV, DWT);
}
Debug::log(LOG, "New mouse has libinput sens %.2f (%.2f) with accel profile %i (%i)", libinput_device_config_accel_get_speed(LIBINPUTDEV), libinput_device_config_accel_get_default_speed(LIBINPUTDEV), libinput_device_config_accel_get_profile(LIBINPUTDEV), libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
}
setMouseConfigs();
PMOUSE->hyprListener_destroyMouse.initCallback(&mouse->events.destroy, &Events::listener_destroyMouse, PMOUSE, "Mouse");
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, mouse);
@@ -565,6 +572,63 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
Debug::log(LOG, "New mouse created, pointer WLR: %x", mouse);
}
void CInputManager::setMouseConfigs() {
for (auto& m : m_lMice) {
const auto PMOUSE = &m;
auto devname = PMOUSE->name;
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
if (wlr_input_device_is_libinput(m.mouse)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(m.mouse);
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "clickfinger_behavior") : g_pConfigManager->getInt("input:touchpad:clickfinger_behavior")) == 0) // toggle software buttons or clickfinger
libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
else
libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
if (libinput_device_config_middle_emulation_is_available(LIBINPUTDEV)) { // middleclick on r+l mouse button pressed
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "middle_button_emulation") : g_pConfigManager->getInt("input:touchpad:middle_button_emulation")) == 1)
libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED);
else
libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED);
}
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "drag_lock") : g_pConfigManager->getInt("input:touchpad:drag_lock")) == 0)
libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_DISABLED);
else
libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_ENABLED);
if (libinput_device_config_tap_get_finger_count(LIBINPUTDEV)) // this is for tapping (like on a laptop)
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "tap-to-click") : g_pConfigManager->getInt("input:touchpad:tap-to-click")) == 1)
libinput_device_config_tap_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_ENABLED);
if (libinput_device_config_scroll_has_natural_scroll(LIBINPUTDEV)) {
double w = 0, h = 0;
if (libinput_device_has_capability(LIBINPUTDEV, LIBINPUT_DEVICE_CAP_POINTER) && libinput_device_get_size(LIBINPUTDEV, &w, &h) == 0) // pointer with size is a touchpad
libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, (HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "natural_scroll") : g_pConfigManager->getInt("input:touchpad:natural_scroll")));
else
libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, (HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "natural_scroll") : g_pConfigManager->getInt("input:natural_scroll")));
}
if (libinput_device_config_dwt_is_available(LIBINPUTDEV)) {
const auto DWT = static_cast<enum libinput_config_dwt_state>((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "disable_while_typing") : g_pConfigManager->getInt("input:touchpad:disable_while_typing")) != 0);
libinput_device_config_dwt_set_enabled(LIBINPUTDEV, DWT);
}
const auto LIBINPUTSENS = std::clamp((HASCONFIG ? g_pConfigManager->getDeviceFloat(devname, "sensitivity") : g_pConfigManager->getFloat("input:sensitivity")), -1.f, 1.f);
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_NONE);
libinput_device_config_accel_set_speed(LIBINPUTDEV, LIBINPUTSENS);
Debug::log(LOG, "Applied config to mouse %s, sens %.2f", m.name.c_str(), LIBINPUTSENS);
}
}
}
void CInputManager::destroyKeyboard(SKeyboard* pKeyboard) {
pKeyboard->hyprListener_keyboardDestroy.removeCallback();
pKeyboard->hyprListener_keyboardMod.removeCallback();
@@ -599,26 +663,11 @@ void CInputManager::destroyMouse(wlr_input_device* mouse) {
}
void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
const auto KEYCODE = e->keycode + 8; // Because to xkbcommon it's +8 from libinput
const xkb_keysym_t* keysyms;
int syms = xkb_state_key_get_syms(wlr_keyboard_from_input_device(pKeyboard->keyboard)->xkb_state, KEYCODE, &keysyms);
const auto MODS = accumulateModsFromAllKBs();
bool passEvent = g_pKeybindManager->onKeyEvent(e, pKeyboard);
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
bool found = false;
if (e->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
for (int i = 0; i < syms; ++i)
found = g_pKeybindManager->handleKeybinds(MODS, keysyms[i], 0) || found;
found = g_pKeybindManager->handleKeybinds(MODS, 0, KEYCODE) || found;
} else if (e->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
// hee hee
}
if (!found) {
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);
}

View File

@@ -17,6 +17,7 @@ public:
void onMouseMoved(wlr_pointer_motion_event*);
void onMouseWarp(wlr_pointer_motion_absolute_event*);
void onMouseButton(wlr_pointer_button_event*);
void onMouseWheel(wlr_pointer_axis_event*);
void onKeyboardKey(wlr_keyboard_key_event*, SKeyboard*);
void onKeyboardMod(void*, SKeyboard*);
@@ -32,6 +33,7 @@ public:
void refocus();
void setKeyboardLayout();
void setMouseConfigs();
void updateDragIcon();
void updateCapabilities(wlr_input_device*);
@@ -75,6 +77,9 @@ public:
CTimer m_tmrLastCursorMovement;
// for shared mods
uint32_t accumulateModsFromAllKBs();
private:
// for click behavior override
@@ -91,9 +96,6 @@ private:
STabletTool* ensureTabletToolPresent(wlr_tablet_tool*);
void applyConfigToKeyboard(SKeyboard*);
// for shared mods
uint32_t accumulateModsFromAllKBs();
};
inline std::unique_ptr<CInputManager> g_pInputManager;

View File

@@ -4,10 +4,21 @@
void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
static auto *const PSWIPE = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe")->intValue;
static auto *const PSWIPEFINGERS = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_fingers")->intValue;
if (e->fingers < 3 || *PSWIPE == 0)
if (e->fingers != *PSWIPEFINGERS|| *PSWIPE == 0)
return;
int onMonitor = 0;
for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
onMonitor++;
}
}
if (onMonitor < 2)
return; // disallow swiping when there's 1 workspace on a monitor
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
Debug::log(LOG, "Starting a swipe from %s", PWORKSPACE->m_szName.c_str());
@@ -40,15 +51,21 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
if ((abs(m_sActiveSwipe.delta) < *PSWIPEDIST * *PSWIPEPERC && (*PSWIPEFORC == 0 || (*PSWIPEFORC != 0 && m_sActiveSwipe.avgSpeed < *PSWIPEFORC))) || abs(m_sActiveSwipe.delta) < 2) {
// revert
if (m_sActiveSwipe.delta < 0) {
// to left
PWORKSPACEL->m_vRenderOffset = Vector2D({-m_sActiveSwipe.pMonitor->vecSize.x, 0});
if (abs(m_sActiveSwipe.delta) < 2) {
PWORKSPACEL->m_vRenderOffset.setValueAndWarp(Vector2D(0,0));
PWORKSPACER->m_vRenderOffset.setValueAndWarp(Vector2D(0,0));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0,0));
} else {
// to right
PWORKSPACER->m_vRenderOffset = Vector2D({m_sActiveSwipe.pMonitor->vecSize.x, 0});
}
if (m_sActiveSwipe.delta < 0) {
// to left
PWORKSPACEL->m_vRenderOffset = Vector2D({-m_sActiveSwipe.pMonitor->vecSize.x, 0});
} else {
// to right
PWORKSPACER->m_vRenderOffset = Vector2D({m_sActiveSwipe.pMonitor->vecSize.x, 0});
}
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D();
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D();
}
} else if (m_sActiveSwipe.delta < 0) {
// switch to left
const auto RENDEROFFSET = PWORKSPACEL->m_vRenderOffset.vec();
@@ -58,6 +75,12 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
PWORKSPACEL->m_vRenderOffset.setValue(RENDEROFFSET);
PWORKSPACEL->m_fAlpha.setValueAndWarp(255.f);
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE);
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(m_sActiveSwipe.pMonitor->vecSize.x, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f);
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr;
Debug::log(LOG, "Ended swipe to the left");
} else {
// switch to right
@@ -68,12 +91,15 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
PWORKSPACER->m_vRenderOffset.setValue(RENDEROFFSET);
PWORKSPACER->m_fAlpha.setValueAndWarp(255.f);
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE);
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-m_sActiveSwipe.pMonitor->vecSize.x, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f);
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr;
Debug::log(LOG, "Ended swipe to the right");
}
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f);
PWORKSPACEL->m_bForceRendering = false;
PWORKSPACER->m_bForceRendering = false;
m_sActiveSwipe.pWorkspaceBegin->m_bForceRendering = false;
@@ -102,6 +128,8 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
if (workspaceIDLeft == INT_MAX || workspaceIDRight == INT_MAX || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID)
return;
m_sActiveSwipe.pWorkspaceBegin->m_bForceRendering = true;
m_sActiveSwipe.delta = std::clamp(m_sActiveSwipe.delta, (double)-*PSWIPEDIST, (double)*PSWIPEDIST);
if (m_sActiveSwipe.delta < 0) {

View File

@@ -2,15 +2,14 @@
#include "OpenGL.hpp"
bool CFramebuffer::alloc(int w, int h) {
bool firstAlloc = false;
if (m_iFb == (uint32_t)-1)
{
bool firstAlloc = false;
if (m_iFb == (uint32_t)-1) {
firstAlloc = true;
glGenFramebuffers(1, &m_iFb);
}
if (m_cTex.m_iTexID == 0)
{
if (m_cTex.m_iTexID == 0) {
firstAlloc = true;
glGenTextures(1, &m_cTex.m_iTexID);
glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID);
@@ -20,13 +19,11 @@ bool CFramebuffer::alloc(int w, int h) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
if (firstAlloc || m_Size != Vector2D(w, h))
{
if (firstAlloc || m_Size != Vector2D(w, h)) {
glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0);
@@ -37,7 +34,6 @@ bool CFramebuffer::alloc(int w, int h) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
glBindTexture(GL_TEXTURE_2D, m_pStencilTex->m_iTexID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_pStencilTex->m_iTexID, 0);
}
@@ -78,3 +74,7 @@ void CFramebuffer::release() {
m_cTex.m_iTexID = 0;
m_iFb = -1;
}
CFramebuffer::~CFramebuffer() {
release();
}

View File

@@ -6,6 +6,8 @@
class CFramebuffer {
public:
~CFramebuffer();
bool alloc(int w, int h);
void bind();
void release();

View File

@@ -31,6 +31,11 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
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;
@@ -40,6 +45,11 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
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;
@@ -49,6 +59,11 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
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;
@@ -58,6 +73,11 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
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;
@@ -66,6 +86,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
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;
@@ -74,18 +96,34 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
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.");
@@ -139,7 +177,7 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) {
return shader;
}
void CHyprOpenGLImpl::begin(SMonitor* pMonitor, pixman_region32_t* pDamage, bool fake) {
void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool fake) {
m_RenderData.pMonitor = pMonitor;
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
@@ -285,11 +323,11 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
// Rounded corners
glUniform2f(m_shQUAD.getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shQUAD.getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shQUAD.getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shQUAD.getUniformLocation("radius"), round);
glUniform1i(m_shQUAD.getUniformLocation("primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0));
glUniform2f(m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shQUAD.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shQUAD.radius, round);
glUniform1i(m_shQUAD.primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0));
glVertexAttribPointer(m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_shQUAD.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
@@ -380,22 +418,22 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
// Rounded corners
glUniform2f(shader->getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(shader->getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(shader->getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(shader->getUniformLocation("radius"), round);
glUniform1i(shader->getUniformLocation("primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
glUniform2f(shader->topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(shader->bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(shader->fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(shader->radius, round);
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
if (allowCustomUV && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) {
const float verts[] = {
m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVTopLeft.y, // top right
m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVTopLeft.y, // top left
m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVBottomRight.y, // bottom right
m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVBottomRight.y, // bottom left
};
const float verts[] = {
m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVTopLeft.y, // top right
m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVTopLeft.y, // top left
m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVBottomRight.y, // bottom right
m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVBottomRight.y, // bottom left
};
if (allowCustomUV && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) {
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
} else {
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
@@ -471,11 +509,11 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
// prep two shaders
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
glUniform1f(pShader->getUniformLocation("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)
glUniform2f(m_shBLUR1.getUniformLocation("halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f));
glUniform2f(m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f));
else
glUniform2f(m_shBLUR2.getUniformLocation("halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f));
glUniform2f(m_shBLUR2.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f));
glUniform1i(pShader->tex, 0);
glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
@@ -567,7 +605,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
}
if (!pixman_region32_not_empty(&inverseOpaque)) {
renderTexture(tex, pBox, a, round, false); // reject blurring a fully opaque window
renderTexture(tex, pBox, a, round, false, true); // reject blurring a fully opaque window
return;
}
@@ -590,7 +628,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
renderTexture(tex, pBox, a, round, true); // discard opaque
renderTexture(tex, pBox, a, round, true, true); // discard opaque
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, 1, -1);
@@ -601,7 +639,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
if (pixman_region32_not_empty(&damage)) {
// render our great blurred FB
static auto *const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue;
renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, true);
renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, false);
// render the window, but clear stencil
glClearStencil(0);
@@ -655,18 +693,18 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
glUseProgram(m_shBORDER1.program);
glUniformMatrix3fv(m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
glUniform4f(m_shBORDER1.getUniformLocation("color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
glUniform4f(m_shBORDER1.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
const auto TOPLEFT = Vector2D(round, round);
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round);
const auto FULLSIZE = Vector2D(box->width, box->height);
glUniform2f(m_shBORDER1.getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shBORDER1.getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shBORDER1.getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shBORDER1.getUniformLocation("radius"), round);
glUniform1f(m_shBORDER1.getUniformLocation("thick"), *PBORDERSIZE);
glUniform1i(m_shBORDER1.getUniformLocation("primitiveMultisample"), *PMULTISAMPLE);
glUniform2f(m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shBORDER1.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shBORDER1.radius, round);
glUniform1f(m_shBORDER1.thick, *PBORDERSIZE);
glUniform1i(m_shBORDER1.primitiveMultisample, *PMULTISAMPLE);
glVertexAttribPointer(m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
@@ -698,12 +736,10 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
// this is temporary, doesnt mess with the actual wlr damage
pixman_region32_t 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);
pixman_region32_fini(&fakeDamage);
clear(CColor(0,0,0,0)); // JIC
timespec now;
@@ -719,6 +755,8 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders, RENDER_PASS_ALL);
m_bEndFrame = true;
g_pConfigManager->setInt("decoration:blur", BLURVAL);
// render onto the window fb
@@ -733,8 +771,10 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
clear(CColor(0, 0, 0, 0)); // JIC
wlr_box fullMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
wlr_box fullMonBox = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &fullMonBox, 255.f, 0);
m_bEndFrame = false;
// restore original fb
#ifndef GLES2
@@ -742,9 +782,10 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
#endif
end();
pixman_region32_fini(&fakeDamage);
wlr_output_rollback(PMONITOR->output);
}
@@ -762,8 +803,6 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
begin(PMONITOR, &fakeDamage, true);
pixman_region32_fini(&fakeDamage);
const auto PFRAMEBUFFER = &m_mLayerFramebuffers[pLayer];
glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y);
@@ -780,6 +819,8 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
// draw the layer
g_pHyprRenderer->renderLayer(pLayer, PMONITOR, &now);
m_bEndFrame = false;
// TODO: WARN:
// revise if any stencil-requiring rendering is done to the layers.
@@ -792,6 +833,8 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
end();
pixman_region32_fini(&fakeDamage);
wlr_output_rollback(PMONITOR->output);
}
@@ -816,17 +859,24 @@ void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) {
// the originalClosedPos is relative to the monitor's pos
Vector2D scaleXY = Vector2D((PMONITOR->scale * PWINDOW->m_vRealSize.vec().x / (PWINDOW->m_vOriginalClosedSize.x * PMONITOR->scale)), (PMONITOR->scale * PWINDOW->m_vRealSize.vec().y / (PWINDOW->m_vOriginalClosedSize.y * PMONITOR->scale)));
windowBox.width = PMONITOR->vecPixelSize.x * scaleXY.x;
windowBox.height = PMONITOR->vecPixelSize.y * scaleXY.y;
// TODO: this is wrong on scaled.
windowBox.width = PMONITOR->vecTransformedSize.x * scaleXY.x;
windowBox.height = PMONITOR->vecTransformedSize.y * scaleXY.y;
windowBox.x = ((PWINDOW->m_vRealPosition.vec().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - ((PWINDOW->m_vOriginalClosedPos.x * PMONITOR->scale) * scaleXY.x);
windowBox.y = ((PWINDOW->m_vRealPosition.vec().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - ((PWINDOW->m_vOriginalClosedPos.y * PMONITOR->scale) * scaleXY.y);
pixman_region32_t fakeDamage;
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y);
renderTextureInternalWithDamage(it->second.m_cTex, &windowBox, PWINDOW->m_fAlpha.fl(), &fakeDamage, 0);
pixman_region32_fini(&fakeDamage);
static auto *const PDAMAGEMON = &g_pConfigManager->getConfigValuePtr("misc:damage_entire_on_snapshot")->intValue;
if (*PDAMAGEMON)
PMONITOR->forceFullFrames += 1;
}
void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) {
@@ -845,26 +895,31 @@ void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PLAYER->monitorID);
wlr_box windowBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
wlr_box windowBox = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
pixman_region32_t fakeDamage;
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.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);
pixman_region32_fini(&fakeDamage);
static auto *const PDAMAGEMON = &g_pConfigManager->getConfigValuePtr("misc:damage_entire_on_snapshot")->intValue;
if (*PDAMAGEMON)
PMONITOR->forceFullFrames += 1;
}
void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, float a) {
RASSERT(m_RenderData.pMonitor, "Tried to render shadow without begin()!");
RASSERT((box->width > 0 && box->height > 0), "Tried to render shadow with width/height < 0!");
RASSERT(m_pCurrentWindow, "Tried to render shadow without a window!");
static auto *const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue;
static auto *const PSHADOWPOWER = &g_pConfigManager->getConfigValuePtr("decoration:shadow_render_power")->intValue;
const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4);
const auto col = CColor(*PSHADOWCOL);
const auto col = m_pCurrentWindow->m_cRealShadowColor.col();
float matrix[9];
wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here
@@ -881,19 +936,19 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
glUseProgram(m_shSHADOW.program);
glUniformMatrix3fv(m_shSHADOW.proj, 1, GL_FALSE, glMatrix);
glUniform4f(m_shSHADOW.getUniformLocation("color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a);
glUniform4f(m_shSHADOW.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a);
const auto TOPLEFT = Vector2D(range + round, range + round);
const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round));
const auto FULLSIZE = Vector2D(box->width, box->height);
// Rounded corners
glUniform2f(m_shSHADOW.getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shSHADOW.getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shSHADOW.getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shSHADOW.getUniformLocation("radius"), range + round);
glUniform1f(m_shSHADOW.getUniformLocation("range"), range);
glUniform1f(m_shSHADOW.getUniformLocation("shadowPower"), SHADOWPOWER);
glUniform2f(m_shSHADOW.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_shSHADOW.radius, range + round);
glUniform1f(m_shSHADOW.range, range);
glUniform1f(m_shSHADOW.shadowPower, SHADOWPOWER);
glVertexAttribPointer(m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
@@ -926,13 +981,13 @@ void CHyprOpenGLImpl::renderSplash(cairo_t *const CAIRO, cairo_surface_t *const
cairo_text_extents_t textExtents;
cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents);
cairo_move_to(CAIRO, m_RenderData.pMonitor->vecPixelSize.x / 2.f - textExtents.width / 2.f, m_RenderData.pMonitor->vecPixelSize.y - textExtents.height - 1);
cairo_move_to(CAIRO, m_RenderData.pMonitor->vecTransformedSize.x / 2.f - textExtents.width / 2.f, m_RenderData.pMonitor->vecTransformedSize.y - textExtents.height - 1);
cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str());
cairo_surface_flush(CAIROSURFACE);
}
void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) {
void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!");
static auto *const PNOSPLASH = &g_pConfigManager->getConfigValuePtr("misc:disable_splash_rendering")->intValue;
@@ -966,6 +1021,8 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) {
texPath += "2K.png";
}
PTEX->m_vSize = textureSize;
// create a new one with cairo
const auto CAIROSURFACE = cairo_image_surface_create_from_png(texPath.c_str());
@@ -988,6 +1045,28 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) {
cairo_surface_destroy(CAIROSURFACE);
cairo_destroy(CAIRO);
// calc the target box
const float MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y;
const float WPRATIO = 1.77f;
Vector2D origin;
float scale;
if (MONRATIO > WPRATIO) {
scale = m_RenderData.pMonitor->vecTransformedSize.x / PTEX->m_vSize.x;
origin.y = -(PTEX->m_vSize.y * scale - m_RenderData.pMonitor->vecTransformedSize.y) / 2.f / scale;
} else {
scale = m_RenderData.pMonitor->vecTransformedSize.y / PTEX->m_vSize.y;
origin.x = -(PTEX->m_vSize.x * scale - m_RenderData.pMonitor->vecTransformedSize.x) / 2.f / scale;
}
wlr_box box = {origin.x * scale, origin.y * scale, PTEX->m_vSize.x * scale, PTEX->m_vSize.y * scale};
m_mMonitorRenderResources[pMonitor].backgroundTexBox = box;
Debug::log(LOG, "Background created for monitor %s", pMonitor->szName.c_str());
}
@@ -997,12 +1076,11 @@ void CHyprOpenGLImpl::clearWithTex() {
static auto *const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
if (!*PRENDERTEX) {
wlr_box box = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &box, 255, 0);
renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &m_mMonitorRenderResources[m_RenderData.pMonitor].backgroundTexBox, 255, 0);
}
}
void CHyprOpenGLImpl::destroyMonitorResources(SMonitor* pMonitor) {
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].primaryFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].stencilTex.destroyTexture();

View File

@@ -37,10 +37,12 @@ struct SMonitorRenderData {
CFramebuffer mirrorSwapFB;
CTexture stencilTex;
wlr_box backgroundTexBox;
};
struct SCurrentRenderData {
SMonitor* pMonitor = nullptr;
CMonitor* pMonitor = nullptr;
float projection[9];
SMonitorRenderData* pCurrentMonData = nullptr;
@@ -56,7 +58,7 @@ public:
CHyprOpenGLImpl();
void begin(SMonitor*, pixman_region32_t*, bool fake = false);
void begin(CMonitor*, pixman_region32_t*, bool fake = false);
void end();
void renderRect(wlr_box*, const CColor&, int round = 0);
@@ -78,7 +80,7 @@ public:
void scissor(const pixman_box32*);
void scissor(const int x, const int y, const int w, const int h);
void destroyMonitorResources(SMonitor*);
void destroyMonitorResources(CMonitor*);
SCurrentRenderData m_RenderData;
@@ -91,8 +93,8 @@ public:
std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers;
std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers;
std::unordered_map<SMonitor*, SMonitorRenderData> m_mMonitorRenderResources;
std::unordered_map<SMonitor*, CTexture> m_mMonitorBGTextures;
std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources;
std::unordered_map<CMonitor*, CTexture> m_mMonitorBGTextures;
private:
std::list<GLuint> m_lBuffers;
@@ -117,7 +119,7 @@ private:
GLuint createProgram(const std::string&, const std::string&);
GLuint compileShader(const GLuint&, std::string);
void createBGTextureForMonitor(SMonitor*);
void createBGTextureForMonitor(CMonitor*);
// returns the out FB, can be either Mirror or MirrorSwap
CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage);

View File

@@ -17,30 +17,34 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
else // here we clamp to 2, these might be some tiny specks
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::clamp(surface->current.width, 2, 1337420), std::clamp(surface->current.height, 2, 1337420)};
// squish all oversized
// squish all oversized but dont in some cases, jesus christ this is a mess
// TODO: this shouldn't be done this way. Custom UV here as well.
// this is fucking horrible
// Issue: will cause oversized apps with reserved area to overflow from the window box. (see chromium on ozone wayland)
const auto PRESQUISHSIZE = Vector2D(windowBox.width, windowBox.height);
if (RDATA->squishOversized) {
if (x + windowBox.width > RDATA->w)
windowBox.width = RDATA->w - x;
if (y + windowBox.height > RDATA->h)
if (y + windowBox.height > RDATA->h)
windowBox.height = RDATA->h - y;
}
scaleBox(&windowBox, RDATA->output->scale);
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
static auto *const PBORDERTHICK = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? *PROUNDING : RDATA->rounding;
rounding += *PBORDERTHICK;
if (RDATA->surface && surface == RDATA->surface) {
if (RDATA->blur)
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding);
else
if (wlr_surface_is_xwayland_surface(surface) && !wlr_xwayland_surface_from_wlr_surface(surface)->has_alpha && RDATA->fadeAlpha * RDATA->alpha == 255.f) {
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
if (RDATA->decorate) {
auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col();
col.a *= RDATA->fadeAlpha * RDATA->alpha / 255.f;
g_pHyprOpenGL->renderBorder(&windowBox, col, rounding);
} else {
if (RDATA->blur)
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding);
else
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
}
}
else {
@@ -48,30 +52,41 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
wlr_box geo;
wlr_xdg_surface_get_geometry(wlr_xdg_surface_from_wlr_surface(RDATA->surface), &geo);
// TODO: continuation of the above madness.
if (geo.x != 0 || geo.y != 0) {
windowBox.width = PRESQUISHSIZE.x;
windowBox.height = PRESQUISHSIZE.y;
}
windowBox.x -= geo.x;
windowBox.y -= geo.y;
}
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false);
}
wlr_surface_send_frame_done(surface, RDATA->when);
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output);
}
bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, SMonitor* pMonitor) {
bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
wlr_box geometry = pWindow->getFullWindowBoundingBox();
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry))
return false;
// now check if it has the same workspace
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID) {
if (!(!PWORKSPACE->m_bHasFullscreenWindow || pWindow->m_bIsFullscreen || (pWindow->m_bIsFloating && pWindow->m_bCreatedOverFullscreen)))
return false;
}
if (pWindow->m_iWorkspaceID == pMonitor->activeWorkspace)
return true;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
// if not, check if it maybe is active on a different monitor. vvv might be animation in progress
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && PWORKSPACE->m_bForceRendering) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
return true;
@@ -103,14 +118,20 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) {
return false;
}
void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) {
void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) {
CWindow* pWorkspaceWindow = nullptr;
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen)
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID);
if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen){
if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
continue;
}
if (w->m_iWorkspaceID == pMonitor->activeWorkspace && !w->m_bIsFullscreen)
continue;
// found it!
renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL, RENDER_PASS_ALL);
pWorkspaceWindow = w.get();
@@ -143,12 +164,12 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor
if (pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL) {
// on non-full we draw the bar and shit
for (auto& ls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
renderLayer(ls, pMonitor, time);
renderLayer(ls.get(), pMonitor, time);
}
}
for (auto& ls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
renderLayer(ls, pMonitor, time);
renderLayer(ls.get(), pMonitor, time);
}
renderDragIcon(pMonitor, time);
@@ -158,7 +179,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor
g_pHyprError->draw();
}
void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode) {
void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode) {
if (pWindow->m_bHidden)
return;
@@ -182,7 +203,6 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true) && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL);
renderdata.rounding = pWindow->m_sAdditionalConfigData.rounding;
renderdata.blur = true; // if it shouldn't, it will be ignored later
renderdata.squishOversized = pWindow->m_vRealPosition.isBeingAnimated();
// apply window special data
if (pWindow->m_sSpecialRenderData.alphaInactive == -1)
@@ -190,6 +210,10 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
else
renderdata.alpha *= pWindow == g_pCompositor->m_pLastWindow ? pWindow->m_sSpecialRenderData.alpha : pWindow->m_sSpecialRenderData.alphaInactive;
// apply opaque
if (pWindow->m_sAdditionalConfigData.forceOpaque)
renderdata.alpha = 1.f;
g_pHyprOpenGL->m_pCurrentWindow = pWindow;
// render window decorations first, if not fullscreen full
@@ -202,6 +226,8 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
wlr_box geom;
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
// first, check for poorly sized windows.
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D((double)geom.x / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)geom.y / (double)pWindow->m_uSurface.xdg->surface->current.height);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D((double)(geom.width + geom.x) / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)(geom.y + geom.height) / (double)pWindow->m_uSurface.xdg->surface->current.height);
@@ -210,6 +236,19 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
// then, if the surface is too big, modify the pos UV
if (geom.width > renderdata.w + 1 || geom.height > renderdata.h + 1) {
const auto OFF = Vector2D(renderdata.w / (double)geom.width, renderdata.h / (double)geom.height);
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D(-1, -1))
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(0, 0);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x * ((double)renderdata.w / ((double)geom.width / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x)),
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y * ((double)renderdata.h / ((double)geom.height / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y))
);
}
} else {
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
@@ -217,6 +256,21 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
if (renderdata.decorate) {
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding;
auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col();
col.a *= renderdata.fadeAlpha * renderdata.alpha / 255.f;
wlr_box windowBox = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h};
scaleBox(&windowBox, pMonitor->scale);
g_pHyprOpenGL->renderBorder(&windowBox, col, rounding);
}
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
@@ -225,6 +279,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
if (!pWindow->m_bIsX11) {
renderdata.dontRound = false; // restore dontround
renderdata.pMonitor = pMonitor;
renderdata.squishOversized = false; // don't squish popups
wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata);
}
}
@@ -232,7 +287,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
g_pHyprOpenGL->m_pCurrentWindow = nullptr;
}
void CHyprRenderer::renderLayer(SLayerSurface* pLayer, SMonitor* pMonitor, timespec* time) {
void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, timespec* time) {
if (pLayer->fadingOut) {
g_pHyprOpenGL->renderSnapshot(&pLayer);
return;
@@ -246,6 +301,9 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, SMonitor* pMonitor, times
renderdata.w = pLayer->layerSurface->surface->current.width;
renderdata.h = pLayer->layerSurface->surface->current.height;
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
renderdata.squishOversized = false; // don't squish popups
wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata);
}
void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
@@ -256,10 +314,10 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
// Render layer surfaces below windows for monitor
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) {
renderLayer(ls, PMONITOR, time);
renderLayer(ls.get(), PMONITOR, time);
}
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) {
renderLayer(ls, PMONITOR, time);
renderLayer(ls.get(), PMONITOR, time);
}
// if there is a fullscreen window, render it and then do not render anymore.
@@ -342,10 +400,10 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
// Render surfaces above windows for monitor
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
renderLayer(ls, PMONITOR, time);
renderLayer(ls.get(), PMONITOR, time);
}
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
renderLayer(ls, PMONITOR, time);
renderLayer(ls.get(), PMONITOR, time);
}
renderDragIcon(PMONITOR, time);
@@ -470,11 +528,11 @@ void apply_exclusive(struct wlr_box* usable_area, uint32_t anchor, int32_t exclu
}
}
void CHyprRenderer::arrangeLayerArray(SMonitor* pMonitor, const std::list<SLayerSurface*>& layerSurfaces, bool exclusiveZone, wlr_box* usableArea) {
void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector<std::unique_ptr<SLayerSurface>>& layerSurfaces, bool exclusiveZone, wlr_box* usableArea) {
wlr_box full_area = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y};
for (auto& ls : layerSurfaces) {
if (ls->fadingOut || ls->readyToDelete || !ls->layerSurface)
if (ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess)
continue;
const auto PLAYER = ls->layerSurface;
@@ -543,7 +601,7 @@ void CHyprRenderer::arrangeLayerArray(SMonitor* pMonitor, const std::list<SLayer
box.y -= PSTATE->margin.bottom;
}
if (box.width <= 0 || box.height <= 0) {
Debug::log(ERR, "LayerSurface %x has a negative/zero w/h???", ls);
Debug::log(ERR, "LayerSurface %x has a negative/zero w/h???", ls.get());
continue;
}
// Apply
@@ -599,7 +657,7 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
// schedule frame events
if (!wl_list_empty(&pSurface->current.frame_callback_list)) {
wlr_output_schedule_frame(g_pCompositor->getMonitorFromVector(Vector2D(x, y))->output);
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y)));
}
if (!pixman_region32_not_empty(&damageBox)) {
@@ -607,23 +665,29 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
return;
}
pixman_region32_translate(&damageBox, x, y);
pixman_region32_t damageBoxForEach;
pixman_region32_init(&damageBoxForEach);
for (auto& m : g_pCompositor->m_vMonitors) {
double lx = 0, ly = 0;
wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, m->output, &lx, &ly);
pixman_region32_translate(&damageBox, lx, ly);
wlr_region_scale(&damageBox, &damageBox, m->scale);
wlr_output_damage_add(m->damage, &damageBox);
pixman_region32_translate(&damageBox, -lx, -ly);
pixman_region32_copy(&damageBoxForEach, &damageBox);
pixman_region32_translate(&damageBoxForEach, x - m->vecPosition.x, y - m->vecPosition.y);
wlr_region_scale(&damageBoxForEach, &damageBoxForEach, m->scale);
pixman_region32_translate(&damageBoxForEach, lx + m->vecPosition.x, ly + m->vecPosition.y);
wlr_output_damage_add(m->damage, &damageBoxForEach);
}
pixman_region32_fini(&damageBox);
pixman_region32_fini(&damageBoxForEach);
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Damage: Surface (extents): xy: %d, %d wh: %d, %d", damageBox.extents.x1, damageBox.extents.y1, damageBox.extents.x2 - damageBox.extents.x1, damageBox.extents.y2 - damageBox.extents.y1);
pixman_region32_fini(&damageBox);
}
void CHyprRenderer::damageWindow(CWindow* pWindow) {
@@ -640,7 +704,7 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) {
Debug::log(LOG, "Damage: Window (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height);
}
void CHyprRenderer::damageMonitor(SMonitor* pMonitor) {
void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
wlr_output_damage_add_box(pMonitor->damage, &damageBox);
@@ -668,7 +732,14 @@ void CHyprRenderer::damageBox(const int& x, const int& y, const int& w, const in
damageBox(&box);
}
void CHyprRenderer::renderDragIcon(SMonitor* pMonitor, timespec* time) {
void CHyprRenderer::damageRegion(pixman_region32_t* rg) {
PIXMAN_DAMAGE_FOREACH(rg) {
const auto RECT = RECTSARR[i];
damageBox(RECT.x1, RECT.y1, RECT.x2 - RECT.x1, RECT.y2 - RECT.y1);
}
}
void CHyprRenderer::renderDragIcon(CMonitor* pMonitor, timespec* time) {
if (!(g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.iconMapped && g_pInputManager->m_sDrag.dragIcon->surface))
return;
@@ -694,19 +765,24 @@ DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string&
return DAMAGE_TRACKING_INVALID;
}
bool CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) {
bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) {
Debug::log(LOG, "Applying monitor rule for %s", pMonitor->szName.c_str());
// if it's disabled, disable and ignore
if (pMonitorRule->disabled) {
wlr_output_enable(pMonitor->output, 0);
wlr_output_commit(pMonitor->output);
Events::listener_monitorDestroy(nullptr, pMonitor->output);
if (pMonitor->m_bEnabled)
pMonitor->onDisconnect();
return false;
}
if (!pMonitor->m_bEnabled) {
pMonitor->onConnect(true); // enable it.
force = true;
}
// 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) {
Debug::log(LOG, "Not applying a new rule to %s because it's already applied!", pMonitor->szName.c_str());
@@ -719,67 +795,81 @@ bool CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecPosition = pMonitorRule->offset;
// loop over modes and choose an appropriate one.
if (!wl_list_empty(&pMonitor->output->modes)) {
wlr_output_mode* mode;
bool found = false;
if (pMonitorRule->resolution != Vector2D()) {
if (!wl_list_empty(&pMonitor->output->modes)) {
wlr_output_mode* mode;
bool found = false;
wl_list_for_each(mode, &pMonitor->output->modes, link) {
// if delta of refresh rate, w and h chosen and mode is < 1 we accept it
if (DELTALESSTHAN(mode->width, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(mode->height, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(mode->refresh / 1000.f, pMonitorRule->refreshRate, 1)) {
wlr_output_set_mode(pMonitor->output, mode);
wl_list_for_each(mode, &pMonitor->output->modes, link) {
// if delta of refresh rate, w and h chosen and mode is < 1 we accept it
if (DELTALESSTHAN(mode->width, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(mode->height, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(mode->refresh / 1000.f, pMonitorRule->refreshRate, 1)) {
wlr_output_set_mode(pMonitor->output, mode);
if (!wlr_output_test(pMonitor->output)) {
Debug::log(LOG, "Monitor %s: REJECTED available mode: %ix%i@%2f!",
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
mode->width, mode->height, mode->refresh / 1000.f);
continue;
}
Debug::log(LOG, "Monitor %s: requested %ix%i@%2f, found available mode: %ix%i@%imHz, applying.",
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
mode->width, mode->height, mode->refresh);
found = true;
pMonitor->refreshRate = mode->refresh / 1000.f;
pMonitor->vecSize = Vector2D(mode->width, mode->height);
break;
}
}
if (!found) {
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
pMonitor->vecSize = pMonitorRule->resolution;
if (!wlr_output_test(pMonitor->output)) {
Debug::log(LOG, "Monitor %s: REJECTED available mode: %ix%i@%2f!",
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f",
(int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
return true;
}
// Preferred is valid
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f",
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
mode->width, mode->height, mode->refresh / 1000.f);
continue;
PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
} else {
Debug::log(LOG, "Set a custom mode %ix%i@%2f (mode not found in monitor modes)", (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
}
Debug::log(LOG, "Monitor %s: requested %ix%i@%2f, found available mode: %ix%i@%imHz, applying.",
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
mode->width, mode->height, mode->refresh);
found = true;
pMonitor->refreshRate = mode->refresh / 1000.f;
pMonitor->vecSize = Vector2D(mode->width, mode->height);
break;
}
}
if (!found) {
} else {
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
pMonitor->vecSize = pMonitorRule->resolution;
if (!wlr_output_test(pMonitor->output)) {
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f",
(int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
return true;
}
// Preferred is valid
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f",
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
} else {
Debug::log(LOG, "Set a custom mode %ix%i@%2f (mode not found in monitor modes)", (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
}
}
} else {
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
pMonitor->vecSize = pMonitorRule->resolution;
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor %s has NO PREFERRED MODE",
(int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
return true;
}
// Preferred is valid
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
}
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
pMonitor->transform = pMonitorRule->transform;

View File

@@ -33,9 +33,10 @@ public:
void damageWindow(CWindow*);
void damageBox(wlr_box*);
void damageBox(const int& x, const int& y, const int& w, const int& h);
void damageMonitor(SMonitor*);
bool applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false);
bool shouldRenderWindow(CWindow*, SMonitor*);
void damageRegion(pixman_region32_t*);
void damageMonitor(CMonitor*);
bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
bool shouldRenderWindow(CWindow*, CMonitor*);
bool shouldRenderWindow(CWindow*);
void ensureCursorRenderingMode();
bool shouldRenderCursor();
@@ -45,11 +46,11 @@ public:
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
private:
void arrangeLayerArray(SMonitor*, const std::list<SLayerSurface*>&, bool, wlr_box*);
void renderWorkspaceWithFullscreenWindow(SMonitor*, CWorkspace*, timespec*);
void renderWindow(CWindow*, SMonitor*, timespec*, bool, eRenderPassMode);
void renderLayer(SLayerSurface*, SMonitor*, timespec*);
void renderDragIcon(SMonitor*, timespec*);
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
void renderWorkspaceWithFullscreenWindow(CMonitor*, CWorkspace*, timespec*);
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode);
void renderLayer(SLayerSurface*, CMonitor*, timespec*);
void renderDragIcon(CMonitor*, timespec*);
bool m_bHasARenderedCursor = true;

View File

@@ -14,6 +14,19 @@ public:
GLint texAttrib;
GLint discardOpaque;
GLint topLeft;
GLint bottomRight;
GLint fullSize;
GLint radius;
GLint primitiveMultisample;
GLint thick;
GLint halfpixel;
GLint range;
GLint shadowPower;
GLint getUniformLocation(const std::string&);
private:

View File

@@ -48,11 +48,14 @@ void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) {
}
}
void CHyprDropShadowDecoration::draw(SMonitor* pMonitor, float a) {
void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) {
if (!g_pCompositor->windowValidMapped(m_pWindow))
return;
if (m_pWindow->m_cRealShadowColor.col() == CColor(0, 0, 0, 0))
return; // don't draw invisible shadows
static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
static auto *const PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue;
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;

View File

@@ -9,7 +9,7 @@ public:
virtual SWindowDecorationExtents getWindowDecorationExtents();
virtual void draw(SMonitor*, float a);
virtual void draw(CMonitor*, float a);
virtual eDecorationType getDecorationType();

View File

@@ -64,7 +64,7 @@ void CHyprGroupBarDecoration::damageEntire() {
g_pHyprRenderer->damageBox(&dm);
}
void CHyprGroupBarDecoration::draw(SMonitor* pMonitor, float a) {
void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) {
// get how many bars we will draw
int barsToDraw = m_dwGroupMembers.size();

View File

@@ -10,7 +10,7 @@ public:
virtual SWindowDecorationExtents getWindowDecorationExtents();
virtual void draw(SMonitor*, float a);
virtual void draw(CMonitor*, float a);
virtual eDecorationType getDecorationType();

View File

@@ -14,7 +14,7 @@ struct SWindowDecorationExtents {
};
class CWindow;
struct SMonitor;
class CMonitor;
interface IHyprWindowDecoration {
public:
@@ -22,7 +22,7 @@ public:
virtual SWindowDecorationExtents getWindowDecorationExtents() = 0;
virtual void draw(SMonitor*, float a) = 0;
virtual void draw(CMonitor*, float a) = 0;
virtual eDecorationType getDecorationType() = 0;

View File

@@ -34,8 +34,7 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar
distances = distances / 4.0;
gl_FragColor = )#" + colorVarName + R"#( * distances;
return;
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
}
}
} else if (pixCoord[1] > bottomRight[1]) {
@@ -66,8 +65,7 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar
distances = distances / 4.0;
gl_FragColor = )#" + colorVarName + R"#( * distances;
return;
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
}
}
}
@@ -102,8 +100,7 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar
distances = distances / 4.0;
gl_FragColor = )#" + colorVarName + R"#( * distances;
return;
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
}
}
} else if (pixCoord[1] > bottomRight[1]) {
@@ -134,8 +131,7 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar
distances = distances / 4.0;
gl_FragColor = )#" + colorVarName + R"#( * distances;
return;
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
}
}
}
@@ -176,11 +172,13 @@ void main() {
return;
}
vec4 pixColor = v_color;
vec2 pixCoord = fullSize * v_texcoord;
)#" + ROUNDED_SHADER_FUNC("v_color") + R"#(
)#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
gl_FragColor = v_color;
gl_FragColor = pixColor;
})#";
inline const std::string TEXVERTSRC = R"#(