Compare commits

..

429 Commits

Author SHA1 Message Date
Vaxry
111d209bff Added toplevel handle sharing Rev2 (#1203)
* Added toplevel handle sharing

* nix: fix build

* update hyprland-protocols

Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
2022-12-12 14:56:42 +00:00
vaxerski
b45a213413 always build with ASan in debug 2022-12-12 14:38:50 +00:00
vaxerski
1a9ee959dd static-ize master opt 2022-12-12 14:37:49 +00:00
Maarten van Gompel
46891b12cf Master layout: lose or inherit fullscreen on deliberate window switching (#1213)
* Master layout: Lose fullscreen status when deliberately switching away from a fullscreen window

* Master layout: implemented inherit_fullscreen config parameter

When set, if you are on a fullscreen window and you cycle to the next,
swap master, etc, it will be automatically fullscreened.
2022-12-12 14:34:52 +00:00
vaxerski
0c1bec023f unset cursor image on end drag if it gets destroyed 2022-12-12 14:32:23 +00:00
vaxerski
80f58bc93f fix blur damage issues with scaled 2022-12-12 14:29:04 +00:00
vaxerski
06e6c6021e fix memory read-after-free in master layout 2022-12-12 14:18:43 +00:00
vaxerski
e8b99ae13a add override to opacity rules 2022-12-11 17:15:02 +00:00
vaxerski
bb99f151da fix pinned offset calc 2022-12-11 16:58:29 +00:00
vaxerski
f97289a3c0 fix rendering multi special ws 2022-12-11 16:53:59 +00:00
Maarten van Gompel
6381b6474f Implement orientation (placement of master area) for master layout (#1202)
* Implemented choosing placement of master area (#1059)

This implement a per workspace 'orientation' that can be set
to left, right, top or bottom. Reflecting placement of the master area.

Left (default) and right are horizontal layouts, top and bottom produce vertical
layouts. Orientation can be switched with: 'hyprctl dispatch layoutmsg orientationleft'
2022-12-10 21:59:16 +00:00
vaxerski
c3f1dc3f52 fix minor issues with move focus and follow mouse 0 2022-12-10 15:15:40 +00:00
vaxerski
62f4503f07 handle constraint cursor hints better 2022-12-10 14:43:46 +00:00
vaxerski
bf78dcecf0 add changefloatingmode event 2022-12-09 18:51:44 +00:00
vaxerski
d5352a5d12 find a default workspace smarter 2022-12-09 17:17:02 +00:00
vaxerski
fd43d2bea7 fix drag resizing on special ws-es 2022-12-09 17:08:04 +00:00
vaxerski
b9812f8bc0 use anim callbacks and don't spam config resets in drag 2022-12-09 15:00:58 +00:00
vaxerski
fba03540d5 fix sharing scaled windows 2022-12-09 14:44:20 +00:00
Mihai Fufezan
11a1a6c271 nix: add xdph to flake and enable it in the nixos module 2022-12-09 16:25:57 +02:00
vaxerski
ff12a41c40 minor focus fixes with LS-es and moving windows 2022-12-09 14:03:37 +00:00
vaxerski
629cca4816 fix string escaping in CMakeLists.txt 2022-12-09 13:57:39 +00:00
Mihai Fufezan
9fc143cf3d Revert "nix: add cachix to nixos module"
This reverts commit 5b7fec481b.
Will clarify better how to enable Cachix, in the wiki.
2022-12-09 13:36:23 +02:00
vaxerski
726732244a sort valid ws-es in relative 2022-12-08 21:24:55 +00:00
vaxerski
be6e1a33b1 ensure mapped state in addViewCoords 2022-12-08 18:52:48 +00:00
vaxerski
6e3bd440ba do not reject drags on visible windows over fullscreen 2022-12-08 17:45:25 +00:00
vaxerski
cba10ba5b7 fix memory safety in getWindowFromSurface 2022-12-08 17:43:15 +00:00
vaxerski
050693be2e fix up relative monitors 2022-12-08 12:09:48 +00:00
vaxerski
0803febac5 optimize m+- and e+- workspace opts 2022-12-08 12:08:41 +00:00
vaxerski
6259202c01 add missing c_str in debug log 2022-12-07 22:47:32 +00:00
vaxerski
e1d7a13333 unset fullscreen in onWindowRemoved 2022-12-07 18:57:02 +00:00
vaxerski
bf5844d607 add failsafe for dwindle windows 2022-12-07 18:57:02 +00:00
Mihai Fufezan
5b7fec481b nix: add cachix to nixos module 2022-12-07 19:18:15 +02:00
vaxerski
73b3bbe49b added nomaxsize rule 2022-12-07 16:08:44 +00:00
vaxerski
d8dcf670da fix lost windows clogging up memory 2022-12-07 14:32:24 +00:00
vaxerski
87b9313034 updated wlroots dep 2022-12-06 23:16:37 +00:00
vaxerski
993c382e74 minor fixes to special workspace behavior 2022-12-06 20:31:44 +00:00
vaxerski
3c9a7811b8 fix up moving to special workspace 2022-12-06 20:20:37 +00:00
vaxerski
6c8d993477 minor toplevel sharing fixups 2022-12-06 18:58:42 +00:00
vaxerski
dfa9277867 remove double semicolons 2022-12-06 15:06:27 +00:00
vaxerski
50e37419e9 fix the release CI 2022-12-06 13:25:24 +00:00
vaxerski
22978aa31e fix tarbomb with source tars 2022-12-06 13:15:18 +00:00
vaxerski
7ed401e5e0 fix group border oversaturation 2022-12-06 12:57:10 +00:00
vaxerski
da76a1ed9e block surface feedback on window sharing 2022-12-05 19:12:15 +00:00
vaxerski
9c67e08dbd ignore alpha when sharing window 2022-12-05 18:00:57 +00:00
vaxerski
6cf716f182 fix handle finding 2022-12-05 17:57:59 +00:00
vaxerski
9fb24ac1e9 avoid using wayland-0 as a socket name 2022-12-05 17:21:09 +00:00
Vaxry
66fb083003 Implement window sharing with the hl toplevel export proto (#1179)
* implement window sharing

Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
2022-12-05 17:05:15 +00:00
vaxerski
20b91f58f8 remove idiotic guard in processMouseDownNormal 2022-12-05 14:30:04 +00:00
vaxerski
ac0e675f3b better capability handling 2022-12-05 14:28:27 +00:00
Mihai Fufezan
f71f04db9e nix: add xdph to nixos module 2022-12-05 03:13:31 +02:00
vaxerski
9e4e98acfb fix crash in blurls remove 2022-12-04 22:34:30 +00:00
eriedaberrie
826e35f7a4 show groupings and swallowing in hyprctl (#1159)
* feat: show groupings and swallowing in hyprctl
2022-12-04 21:03:29 +00:00
Flafy
ffc580dda9 blur xray for layers (#1158)
* feat: apply blur_xray to non window surfaces

* don't blur optimize bottom and background layers
2022-12-04 20:57:41 +00:00
Mihai Fufezan
4557d13a32 nix: update nixpkgs (includes merged hwdata update) 2022-12-04 21:43:28 +02:00
Mihai Fufezan
215c7bd3cb nix: remove merged hwdata override 2022-12-04 21:24:34 +02:00
Flafy
ea2ef63de5 nix: add cmake and wlroots to devshell (#1155) 2022-12-04 19:58:45 +02:00
Paul
d9998f2ca5 Use internal device naming for Hyprctl devices (#1174)
* Use internal naming for Hyprctl devices

* Use c-strings rather than std::string
2022-12-04 17:32:55 +00:00
Flafy
686d6fc6d1 Fix wrong layout recalculate if statement (#1167)
* fix: wrong layout recalculate if statement

* change from find to contains
2022-12-04 17:32:27 +00:00
vaxerski
9e8df888eb fix warning 2022-12-04 00:03:48 +00:00
vaxerski
409ac12f23 avoid duplicate device names 2022-12-03 20:36:52 +00:00
vaxerski
6aa26582f6 added hyprctl switchxkblayout 2022-12-03 16:22:02 +00:00
vaxerski
056a45d035 fix shader destroy id unset 2022-12-03 14:45:10 +00:00
vaxerski
fbc839e8d9 reload shader on dynamic shader keyword 2022-12-03 14:45:10 +00:00
vaxerski
cb85eea261 [gha] build man pages 2022-12-02 20:15:25 +00:00
Hemish
439b827a08 Update wiki link in manpage (#1144)
As wiki is migrated to wiki.hyprland.org, I changed the github wiki link to wiki.hyprland.org in the manpage.
2022-12-02 20:15:03 +00:00
vaxerski
d39d6cc1e3 don't initial focus on LS keyboard grab 2022-12-02 20:10:15 +00:00
vaxerski
d6b3bfc48e don't attempt rendering on begin failure 2022-12-02 19:33:54 +00:00
vaxerski
70d4fadc39 schedule frames and reloads on session re-activate 2022-12-02 18:47:57 +00:00
vaxerski
a2a12018d9 minor changes to unsafe state handling 2022-12-02 18:45:45 +00:00
vaxerski
10d34ef818 added blur_xray 2022-12-02 18:37:11 +00:00
vaxerski
bf52545a91 [gha] bump flake inputs 2022-12-01 21:01:57 +00:00
vaxerski
c012e3d66b update wlroots dep 2022-12-01 21:00:54 +00:00
vaxerski
39a4f82460 fix crash with invalid frag dynamic shaders 2022-12-01 13:40:05 +00:00
vaxerski
7b020ffa84 Added screen shaders 2022-12-01 13:36:07 +00:00
Vaxry
b8ccf3dc3a updated the readme 2022-11-30 22:49:47 +00:00
vaxerski
869f0a0238 remove global var 2022-11-30 13:33:21 +00:00
vaxerski
ff4ea1a13a fix border inner offset in shader 2022-11-29 21:11:37 +00:00
vaxerski
51aebb2845 fix minor issues with blur w/o new optim 2022-11-29 11:21:03 +00:00
vaxerski
212f599412 fix AA on borders 2022-11-29 11:12:29 +00:00
vaxerski
55776df685 fix double free 2022-11-29 11:10:19 +00:00
vaxerski
3dd06b674a clean up blur code and fix minor issues 2022-11-28 19:19:07 +00:00
vaxerski
12df799572 recalculate layout only when needed on dynamic keywords 2022-11-28 19:05:50 +00:00
vaxerski
c341792092 fix minor issues with blur_new_optimize 2022-11-28 19:04:30 +00:00
Eric_Luo
afe12dc90b Fix a compiler warning (#1124)
Co-authored-by: hnboy <hnboy@users.noreply.github.com>
2022-11-28 19:04:24 +00:00
Jef
45d2d1e97d convert bordercolors to GradientValueData correctly (#1122)
Co-authored-by: Jef Steelant <jef.steelant_ext@softathome.com>
2022-11-28 11:44:31 +00:00
vaxerski
0a302901d2 Added handling more special workspaces 2022-11-27 22:42:22 +00:00
vaxerski
49063f949d find floating windows below closed one 2022-11-27 12:11:45 +00:00
vaxerski
7699d657d9 optimize border shader
Do not calculate gradient for discarded fragments
2022-11-27 00:30:44 +00:00
vaxerski
b2cb3b8bf2 use gradients in default configs 2022-11-27 00:26:13 +00:00
vaxerski
6cbaad896c use highp for pixcoord to fix nvidia border issues 2022-11-26 23:55:41 +00:00
vaxerski
9247f88d0c update readme 2022-11-26 20:56:18 +00:00
vaxerski
92f2e342a3 use unreachable instead of break on invalid cvd enum value 2022-11-26 20:46:39 +00:00
Dashie
e2f3f5fe63 Add nofullscreen to windowrules (#1107)
* feat: add windowrule to prevent fullscreen
2022-11-26 20:44:40 +00:00
vaxerski
0db75852f3 fix transformed border thickness 2022-11-26 20:36:05 +00:00
vaxerski
afe688e6ab allow 360 degrees of freedom in gradients 2022-11-26 19:37:20 +00:00
vaxerski
493fc00953 fix decorations missing after no_gaps_when_only toggle floating 2022-11-26 18:48:16 +00:00
vaxerski
c709dc5e8e fix fadeout with animated border 2022-11-26 18:41:30 +00:00
vaxerski
684c59e5bc optimize data feeding to gradient renderer 2022-11-26 18:09:57 +00:00
vaxerski
0948b078e1 added border gradients 2022-11-26 17:57:02 +00:00
vaxerski
52c0356900 monitor rule fixes 2022-11-26 15:41:08 +00:00
vaxerski
1c9a0be8c4 fix up the border shader 2022-11-26 13:51:30 +00:00
vaxerski
f45ec24977 don't focus back after dnd on follow mouse 1 2022-11-26 00:00:36 +00:00
vaxerski
75b7e661e7 damage windows after switch 2022-11-25 19:52:23 +00:00
vaxerski
381d7a4300 check for special workspace open in attemptDirectScanout 2022-11-25 18:25:04 +00:00
vaxerski
0e6e8461eb reset m_bEmptyFocusCursorSet on workspace switch 2022-11-25 11:34:52 +00:00
Mihai Fufezan
141456dd89 Nix & meson: 0.17.0 -> 0.18.0 2022-11-25 08:34:23 +02:00
vaxerski
9616dc7bd8 don't change alpha on special anims 2022-11-24 20:51:33 +00:00
vaxerski
379597e78f remove redundant strval_empty checks 2022-11-24 17:11:21 +00:00
vaxerski
f6067816fb skip covered windows on fullscreen workspaces in getWindowInDirection 2022-11-23 23:40:05 +00:00
vaxerski
750eb76df3 default blur new optimizations to 1 2022-11-23 15:41:19 +00:00
Julian Schuler
79a9bc9076 Add option for retrieving first empty workspace (#1085) 2022-11-23 14:10:26 +00:00
vaxerski
dcb6a0425c override force opaque rule on keybind 2022-11-23 09:55:52 +00:00
vaxerski
e15a9f3d7d damage monitor on group switch 2022-11-22 23:47:00 +00:00
vaxerski
b0f95c63c9 fix crash in setActiveMonitor null 2022-11-22 23:17:10 +00:00
vaxerski
5327565b33 remove resize transitions 2022-11-22 17:20:58 +00:00
vaxerski
95047fb083 return full monitor box for fullscreen windows in idealBB 2022-11-21 23:33:53 +00:00
CactiChameleon9
f00b2fd509 Fix swiping on the first workspace going to the last (#1067) 2022-11-21 23:30:26 +00:00
vaxerski
eb86e7967f add scroll_button libinput opt 2022-11-21 23:26:18 +00:00
Maks
88874fcfe2 Fix cmake error when using clang (#1009) 2022-11-21 21:20:51 +00:00
vaxerski
d504c1e5ab fix master resizes all 2022-11-21 18:14:25 +00:00
vaxerski
c78db1212b Unify rounding shaders 2022-11-21 18:09:47 +00:00
vaxerski
be03a6186c fix invisible windows on moving fullscreen out 2022-11-20 18:50:27 +00:00
Julian Schuler
41a8975bd1 Render focused window at last (#1060) 2022-11-20 18:50:01 +00:00
vaxerski
254c3d166f don't send motion events to lock constraints 2022-11-20 18:38:53 +00:00
vaxerski
137cf9e582 improve constraint handling 2022-11-20 17:35:13 +00:00
Mihai Fufezan
11e841580f Nix: add libdrm and wayland-protocols overlay
fixes #1055
2022-11-20 17:34:11 +02:00
vaxerski
f8b9138383 make focus/swap master layoutmsgs two-way 2022-11-20 11:55:50 +00:00
Narice
c03e4c36b0 Setting wayland environment variables at startup (#1045)
* Nix modules: removed GDK_BACKEND env variable

* setting wayland environment variables at startup

setting XDG_BACKEND and _JAVA_AWT_WM_NONREPARENTING in main.cpp
removed these variables from nix modules recommended environemnt
removed XCURSOR_SIZE from nix modules as it is already set

* Making _JAVA_AWT_WM_NONREPARENTING not overwritten
2022-11-19 19:37:16 +00:00
vaxerski
5530cf6e79 respect no_gaps_when_only in fullscreen 1 2022-11-19 17:35:37 +00:00
vaxerski
1f72237291 Fix incorrect layout positions in mirror re-add 2022-11-19 16:58:14 +00:00
vaxerski
e427d9f622 unify setting of the active monitor 2022-11-19 16:41:41 +00:00
vaxerski
f88feec02b [gha] bump flake inputs 2022-11-19 16:29:06 +00:00
vaxerski
df132e5ff3 update wlroots dep 2022-11-19 16:28:04 +00:00
vaxerski
0ffaa8d667 Fix minor issues with mirrors 2022-11-19 13:14:55 +00:00
vaxerski
e887149f25 minor fixes for mirrors & log more monitor events 2022-11-19 13:01:32 +00:00
vaxerski
250d61e0b3 find base surface if no subsurface found in ls 2022-11-18 20:35:15 +00:00
vaxerski
ba05c43ae3 minor monitor code fixups 2022-11-18 14:15:19 +00:00
vaxerski
82fe530045 don't set AS in onConnect 2022-11-18 14:08:34 +00:00
vaxerski
f91f3d1c81 Reset callbacks on remap 2022-11-18 13:53:54 +00:00
vaxerski
5d39223239 fix events in changeworkspace with bound ws-es 2022-11-17 21:58:22 +00:00
vaxerski
d2a7e22efd more memory safety around onDisconnect 2022-11-17 21:52:45 +00:00
vaxerski
724e411ffc avoid header clashes in make all 2022-11-17 18:27:50 +00:00
vaxerski
c02bfc3897 fix extents in shadow deco 2022-11-16 15:35:36 +00:00
vaxerski
878a20741b fix slide calcs for windows outside the viewport 2022-11-16 15:35:36 +00:00
vaxerski
d5eafe1926 set cursor to hand1 when moving a window 2022-11-15 10:39:05 +00:00
Mihai Fufezan
e2da4ff257 Nix CI: update actions (#1014) 2022-11-15 10:23:46 +00:00
Jef
dbb6732743 apply some rules dynamically when state of window changes (#1020)
Co-authored-by: Jef Steelant <jef.steelant_ext@softathome.com>
2022-11-15 10:21:26 +00:00
Jef
4034aa2c60 possible crash when current workspace does not exist (#1023)
Co-authored-by: Jef Steelant <jef.steelant_ext@softathome.com>
2022-11-15 10:18:04 +00:00
vaxerski
fcb5037a1d guard lastwindow in circlenext 2022-11-14 12:12:13 +00:00
vaxerski
0634abf168 remove quotes from commit messages in build 2022-11-13 20:01:30 +00:00
vaxerski
478fa7cafe Revert "Set child stdout and stderr to /dev/null (#1000)"
This reverts commit 1e5cab1ee7.

Breaks a bunch of stuff, e.g. Waybar.
2022-11-13 19:53:27 +00:00
Jef
549fdf63f6 Add bordercolor windowrule (#992)
* Add bordercolor windowrule

* remove spaces form bordercolor rule + typo

Co-authored-by: Jef Steelant <jef.steelant_ext@softathome.com>
2022-11-13 19:33:13 +00:00
Mihai Fufezan
1a14841a75 Nix: add hwdata overlay (#1010) 2022-11-13 19:32:15 +00:00
vaxerski
a7ed3a5e47 fix arch ci 2022-11-13 14:41:26 +00:00
vaxerski
884fc4f89c fix master window finding on closed 2022-11-13 14:31:12 +00:00
Thomas Voss
1e5cab1ee7 Set child stdout and stderr to /dev/null (#1000)
Some scripts or utilities check to see if stdout or stderr are connected
to a TTY or not to determine certain behaviors (for example, you might
want to prompt a user for input with fzf(1) if in a terminal but tofi(1)
or wofi(1) when spawned from your WM).  Since hyprland never closes
these output streams for spawned processes, they end up just spewing
their output onto the TTY while giving the user no real way to have a
script detect if it's being run from the shell or WM.

Instead of just closing stdout and stderr though, we close them and then
proceed to reopen them but connect them to /dev/null.  This allows
scripts and processes to not fail when attempting to write, but for that
writing to simply have no effect.
2022-11-13 11:58:20 +00:00
vaxerski
5a00f0c657 fix trailing comma in hyprctl activewindow 2022-11-13 11:12:11 +00:00
vaxerski
2cbb10d850 [gha] bump flake inputs 2022-11-13 11:05:51 +00:00
vaxerski
23cd1b8c66 update wlroots dep 2022-11-13 11:04:28 +00:00
vaxerski
be6f5ce831 fix commit message parsing in cmake 2022-11-13 10:58:46 +00:00
Jef
78a545112a streamline hypctl output of windows (#983)
Co-authored-by: Jef Steelant <jef.steelant_ext@softathome.com>
2022-11-13 00:39:21 +00:00
Vaxry
2cdabf581e Merge pull request #997 from leftas/main
Add keyboards' leds update on Key/Mod press
2022-11-12 21:00:38 +00:00
Leftas
34a7f17956 Add keyboard led update after keys/mod update 2022-11-12 13:12:37 +02:00
vaxerski
dd11434e90 notify idle on touch down 2022-11-11 23:41:04 +00:00
vaxerski
61995e3b4e guard empty str in isNumber 2022-11-11 14:04:35 +00:00
sioodmy
13befbd266 fix(nix): missing dependency 2022-11-11 14:43:45 +02:00
vaxerski
a5ffd44caf guard empty str in removeBeginEndSpacesTabs 2022-11-10 21:51:46 +00:00
vaxerski
0208dff574 fix invalid master slave pos calc on y != 0 2022-11-10 19:39:16 +00:00
vaxerski
3157bebed7 fix warning 2022-11-10 17:07:26 +00:00
vaxerski
c0bb4db15c add move cursor windowrule 2022-11-10 16:59:08 +00:00
Philip Jones
27cada2a02 Allow arguments to hyprctl dispatch exec commands. (#990) 2022-11-10 15:36:36 +00:00
vaxerski
153c99217d use spawn in config exec 2022-11-10 13:50:16 +00:00
vaxerski
851df11eb5 Added exec rules 2022-11-10 13:39:23 +00:00
vaxerski
5f2c741f49 remove spammy ime logs 2022-11-10 12:24:41 +00:00
vaxerski
9a9ecc25db added monitor cycling 2022-11-10 12:22:19 +00:00
vaxerski
34b145ee65 Added resizing individual master windows 2022-11-10 12:05:22 +00:00
vaxerski
f41fe59cb6 fix shadow extent & offset calculations 2022-11-09 22:39:19 +00:00
vaxerski
7ff1fd9d69 use goal values in changeWindowFloatingMode 2022-11-09 22:02:02 +00:00
vaxerski
d0b3cdc835 Fix crashes with DS and mirrors 2022-11-09 10:56:49 +00:00
vaxerski
1cf829c889 minor loose focus fixes 2022-11-08 20:28:41 +00:00
vaxerski
17992b633d minor fixes for follow_mouse 3 2022-11-08 14:48:17 +00:00
vaxerski
c545ab4993 Added multiple master layoutmsgs 2022-11-08 12:39:52 +00:00
vaxerski
1d2e4243dc clamp shadow scale to 1 2022-11-07 22:51:26 +00:00
vaxerski
aefc34b405 Minor fixes for virtual input devices 2022-11-07 22:22:13 +00:00
vaxerski
2a20cf5379 Added decoration:shadow_scale 2022-11-07 21:27:28 +00:00
vaxerski
e3a3837164 fix up formatting 2022-11-07 20:31:56 +00:00
Jan Beich
c86ab4694c meson: explicitly specify path for find(1) (#971)
src/meson.build:1:0: ERROR: Command "/usr/bin/find -name *.cpp" failed with status 1.
2022-11-07 20:27:06 +00:00
Jan Beich
5d5066570c helpers: implement getPPIDof on BSDs (#972)
Get PPID from `struct kinfo_proc` via sysctl for the specified PID.
Adjusted for minor differences between each BSD kernel.
2022-11-07 20:26:23 +00:00
abbadanor
1a55fb4170 Dispatcher to center floating window (#961)
Co-authored-by: Adam Nord <adam.nord@abbgymnasiet.se>
Co-authored-by: vaxerski <vaxry@vaxry.net>
2022-11-07 12:16:30 +00:00
vaxerski
efbc3f8194 resize transition fixes + default transitions to false 2022-11-06 18:10:53 +00:00
vaxerski
f755351511 Fix resize transitions on multimon + transformed 2022-11-06 18:04:30 +00:00
vaxerski
57817f7252 Added resize transitions 2022-11-06 17:52:09 +00:00
vaxerski
b4c45aa2e3 fix compiler warning 2022-11-06 14:28:15 +00:00
vaxerski
5295244026 Revert adding toggle for drm scanout flags
This reverts commit 12697d2b72.

Stupid idea.
2022-11-06 14:25:53 +00:00
vaxerski
082f439db2 fix issues with direct scanout's lack of surface frame feedback 2022-11-06 14:20:03 +00:00
vaxerski
12697d2b72 added toggle for drm scanout flags 2022-11-06 14:11:37 +00:00
vaxerski
976b44443a ignore constraints on exclusiveClient create 2022-11-05 18:34:26 +00:00
vaxerski
6553fb5a40 fix fullscreen maximize size 2022-11-05 18:25:32 +00:00
vaxerski
bee06f3507 add more wlroots flags for faster compile 2022-11-05 18:05:15 +00:00
vaxerski
5a750b485a Added creating / destroying outputs on a multi-backend + headless backend
See `hyprctl output`.
2022-11-05 18:04:44 +00:00
vaxerski
a71f44baa5 fix compiler warning 2022-11-05 13:49:55 +00:00
vaxerski
65db3a7bd3 fix relative protocol paths
CI fix
2022-11-05 13:46:58 +00:00
vaxerski
22384869a6 fix unregistering avars on sethidden 2022-11-05 13:37:57 +00:00
vaxerski
ff76fbe763 prevent double-registering of avars 2022-11-05 13:37:29 +00:00
vaxerski
cfbab453e8 move no_direct_scanout to misc 2022-11-05 13:22:18 +00:00
vaxerski
6a59b57ef8 remove spammy logs for DS 2022-11-05 13:06:48 +00:00
vaxerski
f50c786640 Added direct scanout 2022-11-05 12:50:47 +00:00
vaxerski
70aece8522 constraint focus simplifications 2022-11-04 18:09:40 +00:00
vaxerski
c9eb0f3aab fix missing stub for xwayland 2022-11-04 16:10:10 +00:00
vaxerski
206360177f Multiple animation optimization and xwayland wine fixes 2022-11-04 15:56:31 +00:00
vaxerski
34ad837fd9 don't update the env in session-less hl 2022-11-04 11:30:25 +00:00
vaxerski
e796157672 fix passing input to constrained windows without relative 2022-11-04 11:09:34 +00:00
vaxerski
b51222c004 fix ordering in mouse connect 2022-11-04 10:48:42 +00:00
vaxerski
9aad352789 automatically update dbus environment on start 2022-11-04 10:37:14 +00:00
vaxerski
ce8c20c1ed fix raw exec in configmanager 2022-11-04 10:33:05 +00:00
vaxerski
349afa0e7a guard header windows in layout messages 2022-11-03 22:55:44 +00:00
vaxerski
748a6965ca include utility in defines 2022-11-03 19:55:20 +00:00
vaxerski
97af7c416e added unset rules 2022-11-03 19:52:43 +00:00
vaxerski
47512dd6db remove redundant includes 2022-11-03 19:52:34 +00:00
vaxerski
653b9ed0e4 Fix missing focusedmon event on focusmonitor dispatcher 2022-11-03 19:34:26 +00:00
vaxerski
d0e47d9fe0 added workspace_swipe_forever 2022-11-03 13:35:34 +00:00
Mihai Fufezan
f978368a4e Nix HM: Fix invalid escapes
Fixes #949
2022-11-03 13:21:51 +02:00
vaxerski
c47581fc5a handle transforming displays in outputMgr 2022-11-03 09:06:44 +00:00
vaxerski
31aa357c17 fix safety over ls outputs 2022-11-03 08:56:47 +00:00
vaxerski
6ddfae0a07 remove ensureFDsValid, legacy 2022-11-02 21:28:08 +00:00
Mihai Fufezan
0d7176792b Nix HM: prevent race condition between dbus and systemd
Fixes #940
2022-11-02 21:36:07 +02:00
vaxerski
c1542da18a fix typo in focus 2022-11-02 18:54:41 +00:00
vaxerski
5b548f5bc3 update window values after map finish 2022-11-02 15:15:39 +00:00
vaxerski
5ac2005318 remove old comments 2022-11-02 14:52:36 +00:00
vaxerski
a2b8e3b34e fix the damageBox in damageMonitor 2022-11-02 11:04:17 +00:00
vaxerski
d78b53968f render the debug overlay only on visible monitors 2022-11-02 10:24:43 +00:00
abbadanor
61b950d942 Add focusmaster dispatcher (#942)
* added focusmaster dispatcher

* format

Co-authored-by: Adam Nord <adam.nord@abbgymnasiet.se>
Co-authored-by: vaxerski <43317083+vaxerski@users.noreply.github.com>
2022-11-02 10:15:11 +00:00
vaxerski
a16073a87b deprecate general:damage_tracking 2022-11-02 10:12:33 +00:00
vaxerski
603a90886f fix swipe on 2 detached workspaces 2022-11-02 10:01:13 +00:00
vaxerski
95bbac8791 remove redundant check in CShader 2022-11-01 18:46:51 +00:00
vaxerski
a69fd21a1a Add an idleinhibit windowrule 2022-10-31 12:26:07 +00:00
Mihai Fufezan
b6e33830af Nix & meson: 0.16.0 -> 0.17.0
Nix: make xwayland dependencies optional
2022-10-31 12:41:31 +02:00
wael
2c67c1c4f8 meson: use gl instead of GL
`/usr/lib/pkgconfig/gl.pc`
2022-10-31 12:39:04 +02:00
vaxerski
989deafd5e use lld instead of i in hyprctl getopt for accurate int reads 2022-10-30 22:45:03 +00:00
vaxerski
9f1d7f7fc7 properly scan for subsurfaces in fullscreen input refocus 2022-10-30 12:28:37 +00:00
vaxerski
6245c92bd0 avoid creating bound WS-es in moveWorkspaceToMonitor 2022-10-30 12:14:12 +00:00
vaxerski
2e32e202e9 set lastmonitor in onDisconnect 2022-10-29 22:45:01 +01:00
vaxerski
d994ad75e8 revert output smart layout reporting 2022-10-29 17:32:03 +01:00
vaxerski
2caebb3b10 fix default 0 in box passing test 2022-10-29 14:37:33 +01:00
vaxerski
05f3eebd96 avoid layout changes when unnecessary in applyMonitorRule 2022-10-29 12:24:44 +01:00
vaxerski
74d05d0adc ensure VRR for current display only in onConnect 2022-10-28 23:48:48 +01:00
vaxerski
341a0616aa avoid applying offset twice in onConnect 2022-10-28 23:23:23 +01:00
vaxerski
ea7f617df6 remove redundant check 2022-10-28 22:33:47 +01:00
vaxerski
644c64d79d lower IME errors to WARNs 2022-10-28 21:47:08 +01:00
vaxerski
d193d70ecf guard primaryFB tex in end() 2022-10-28 21:46:19 +01:00
vaxerski
9e227a52c0 allow cyclenext on null focus 2022-10-28 21:31:39 +01:00
vaxerski
1a767b021b fix minor focus oopsie 2022-10-28 20:12:17 +01:00
vaxerski
83e4006b16 properly find the constraint window 2022-10-28 19:35:02 +01:00
vaxerski
1759b0483c constrain mouse on focus change 2022-10-28 19:20:12 +01:00
vaxerski
f7174acc48 minor fixes for xwayland refocus 2022-10-28 19:18:10 +01:00
vaxerski
c2cd718e89 ignore pointer constraints in touch 2022-10-27 23:44:23 +01:00
Hilton Chain
c21808dd2d meson: Fallback to 'opengl' when 'GL' is not found.
This patch adds 'opengl' as a fallback to 'GL' for dependency lookup, to
link with libglvnd configured without X11 support.

For OpenGL, libglvnd provides two pkg-config files: `gl.pc' with GLX
support while `opengl.pc' not.  When building without X11 support, the
former won't be installed.
2022-10-28 00:50:58 +03:00
Vaxry
2c2e35eec1 Merge pull request #912 from riley-martin/hyprctl
Improve several hyprctl commands
2022-10-27 16:17:15 +01:00
Riley Martin
c064711d2a Improve hyprctl
Added better help for some hyprctl commands.
Failed commands should now 'fail' by returning a nonzero status to the shell

Fix typos
2022-10-27 10:39:21 -04:00
vaxerski
7d6ccca695 add 10bit support to displays 2022-10-27 13:26:47 +01:00
vaxerski
28c81fc71e add disabling pointer devices 2022-10-27 12:58:10 +01:00
Vaxry
d5a0610ea2 No xwayland overhaul (#920) 2022-10-27 11:26:35 +01:00
vaxerski
4aebb73de0 Added hyprctl cursorpos 2022-10-26 13:19:37 +01:00
vaxerski
46e51a81c4 unrestrict hyprctl message size 2022-10-26 13:11:05 +01:00
vaxerski
83ad59fae7 Allow 100%- for move rule 2022-10-26 12:34:26 +01:00
vaxerski
f9a7b6bf26 default focus_on_activate to false 2022-10-25 18:53:18 +01:00
vaxerski
cdb331076a allow # escaping in config 2022-10-25 14:32:25 +01:00
vaxerski
ba9a8a9ded unify LS unmap focus 2022-10-25 14:19:24 +01:00
vaxerski
34bd2cf803 respect wsbind in workspace silent rules 2022-10-25 10:30:25 +01:00
vaxerski
69f1d7b360 Rework workspace rules 2022-10-24 18:36:31 +01:00
vaxerski
e0bc952c83 minor fix to silent ws rules 2022-10-24 17:00:08 +01:00
vaxerski
cf869d9636 allow nofocus + workspace silent 2022-10-24 12:37:07 +01:00
vaxerski
077c1491a8 respect nofocus in candidate searching 2022-10-24 12:28:41 +01:00
vaxerski
c04563734e Rework candidate finding on close window 2022-10-24 12:25:36 +01:00
vaxerski
1d0d350fc3 fix silent + size windowrules 2022-10-24 12:03:15 +01:00
vaxerski
d55338a3f5 fix debug nest black screen 2022-10-24 11:58:07 +01:00
vaxerski
c6a3092b45 more safety around shutting down and mouse movements 2022-10-24 00:14:42 +01:00
vaxerski
10303259f7 always report sizes after a window unmap 2022-10-22 22:10:34 +01:00
Mihai Fufezan
3dca2fd61e Nix: override wayland-protocols 2022-10-23 00:01:55 +03:00
vaxerski
47eac4be1c disable adaptive sync with no_vfr off 2022-10-22 21:45:17 +01:00
vaxerski
2995867760 Transpose matrices on LEGACY_RENDERER 2022-10-22 21:10:49 +01:00
vaxerski
c132f5a91f [gha] bump flake inputs 2022-10-22 20:02:58 +00:00
vaxerski
24587492dd update wlroots dep 2022-10-22 21:01:45 +01:00
vaxerski
44cee0f5f8 more safety for focus requests 2022-10-22 16:45:33 +01:00
vaxerski
2c714eace5 handle activate requests 2022-10-22 16:43:47 +01:00
vaxerski
0d7d7a970d fix crash in event manager on hangup 2022-10-22 16:15:52 +01:00
Vaxry
3a27ef5e12 Merge pull request #893 from wael444/main
meson.build,CMakeLists.txt: use sh instead of bash
2022-10-22 11:57:36 +01:00
wael
6d273c8e44 CMakeLists.txt: use sh instead of bash 2022-10-22 09:23:52 +03:00
wael
c775153e01 meson.build: use sh instead of bash 2022-10-22 09:23:26 +03:00
vaxerski
b71d7c9007 minor workspace rule parsing fixes 2022-10-21 10:45:12 +01:00
vaxerski
ce5f025428 T1C: window dance compat 2022-10-20 22:38:49 +01:00
vaxerski
6df6aea1ba fix swipe with fullscreen maximized 2022-10-20 20:37:37 +01:00
Kainoa Kanter
ca2d2db0ef Add windowrules for noblur and noshadow (#884) 2022-10-20 20:36:27 +01:00
vaxerski
1ccb0b5f96 bump xdg ver to 5 2022-10-20 18:04:21 +01:00
vaxerski
c2545b3ae6 fix refocus on last window 2022-10-20 18:00:29 +01:00
vaxerski
dada872981 minor swipe on new fixes 2022-10-20 17:52:17 +01:00
vaxerski
1eec5161bd minor fix for swipes from empty workspaces 2022-10-20 15:47:35 +01:00
vaxerski
53c3644c29 fix minor anim issue with swipe new 2022-10-20 15:02:46 +01:00
vaxerski
6d66dde208 added swipe create new 2022-10-20 14:54:32 +01:00
vaxerski
1b349f79ac don't set custom mode in change 2022-10-19 22:12:02 +01:00
vaxerski
da8be82c9a Fix self-noding in changeWindowFloatingMode 2022-10-19 21:32:30 +01:00
vaxerski
8ffd244ef6 fix animate_manual_resizes with moves 2022-10-19 21:17:49 +01:00
vaxerski
bf9d31ce49 fix maximized windows not hiding tiled 2022-10-19 15:17:35 +01:00
vaxerski
98a32f5e52 render layer snapshot without blur 2022-10-19 11:00:59 +01:00
vaxerski
dc1737f128 allow glob wildcard in addreserved 2022-10-17 23:23:07 +01:00
Mihai Fufezan
48634d7e4a Nix & meson: 0.15.3 -> 0.16.0 2022-10-18 01:16:44 +03:00
vaxerski
ecf0cdaba4 a bit more default config nice addons 2022-10-17 16:59:52 +01:00
vaxerski
286cb90c48 ignore OR windows' size hints 2022-10-17 14:26:18 +01:00
vaxerski
3f77cde50e set XCURSOR_SIZE if not set in init 2022-10-17 14:01:04 +01:00
vaxerski
1145654987 default & example config overhaul 2022-10-17 13:48:21 +01:00
vaxerski
da4cfb9c32 use size hints when available in xwayland default geom 2022-10-17 11:18:45 +01:00
vaxerski
58375bc87a Add support for rgba() and rgb() colors in the config 2022-10-16 22:26:02 +01:00
Vaxry
83d99ce5bd Merge pull request #857 from K1llf0rce/max_size_rule
add maxsize window rule
2022-10-15 20:09:14 +01:00
K1llf0rce
dca30815b0 add maxsize window rule 2022-10-15 17:04:57 +02:00
vaxerski
edeb759bb1 add loose focus behavior 2022-10-15 14:13:21 +01:00
Mihai Fufezan
610d4d9473 Nix: update nixpkgs 2022-10-15 02:21:13 +03:00
Mihai Fufezan
f30e572e00 Nix & meson: 0.15.0beta -> 0.15.3beta
Nix: remove merged libdrm update
2022-10-15 01:40:25 +03:00
vaxerski
34cd8b125a rework focus system to be more safe and faster 2022-10-14 20:46:32 +01:00
vaxerski
b0544dbfff remove old log 2022-10-14 14:25:28 +01:00
vaxerski
a7bdfc06ca added bringactivetotop dispatcher 2022-10-14 14:22:31 +01:00
Narice
7e7cb40909 Nix modules: fix environment variables 2022-10-14 16:19:14 +03:00
vaxerski
724fa4a7d4 add touch binding to output 2022-10-14 12:38:44 +01:00
Vaxry
cee0645fd1 Merge pull request #813 from histausse/touch_dev_rotation
Add input:touchdevice:transform config
2022-10-14 12:26:31 +01:00
vaxerski
df9409b8a2 rename transform in DC to touch_transform 2022-10-14 12:23:11 +01:00
Vaxry
f274a70edf Merge pull request #852 from NotAShelf/patch-1
add `PKGBUILD` to ignored files
2022-10-14 11:11:28 +01:00
NotAShelf
ef24a27ade add PKGBUILD to ignored files 2022-10-14 11:46:34 +03:00
vaxerski
670d6ce8f4 fix windowsOut disabled with fadeOut enabled 2022-10-13 21:32:28 +01:00
Vaxry
f3917f2122 Merge pull request #844 from brodi1/hyprctl-json-fix
fix invalid json output by adding a missing comma
2022-10-13 15:32:46 +01:00
Brodi
5d6e56b67c fix invalid json output by adding a missing comma 2022-10-13 16:21:58 +02:00
vaxerski
624303bfb9 check for same workspace in workspace rule 2022-10-13 15:19:30 +01:00
vaxerski
eb3c132fc5 set workspace name in previous 2022-10-13 15:17:16 +01:00
vaxerski
170def35d7 simplify shouldRenderWindow and fix one cond 2022-10-12 18:37:11 +01:00
vaxerski
2ee9fb0675 don't recalc offset on monitor reload offset auto 2022-10-12 15:16:31 +01:00
vaxerski
1396d2a39b fix crash in renderWorkspaceWithFullscreenWindow 2022-10-11 20:29:51 +01:00
vaxerski
7ecc41db9c unsetenv on no XWayland 2022-10-11 12:00:06 +01:00
vaxerski
7ffe4eda12 [gha] build man pages 2022-10-11 10:58:53 +00:00
Simplykyle
25756afad5 Add debug coredump instructions (#812) 2022-10-11 11:58:26 +01:00
vaxerski
8880298f50 [gha] bump flake inputs 2022-10-11 09:33:36 +00:00
vaxerski
d89355f0a6 update wlroots 2022-10-11 10:32:11 +01:00
Vaxry
ae91f6610f Merge pull request #825 from Dickby/Fix_nproc_in_Makefile
Replace $(nproc) with $(shell nproc).
2022-10-10 22:36:10 +01:00
Felix Dick
6e7143e0f5 Replace $(nproc) with $(shell nproc). 2022-10-10 17:13:56 +02:00
Vaxry
f55f56f260 Merge pull request #823 from Dickby/simplify_matrix_calculations
Simplify matrix calculations
2022-10-10 15:59:25 +01:00
Histausse
6287f2b71b use static for transformation matrices 2022-10-10 12:52:12 +02:00
Felix Dick
7e781f24c5 Merge branch 'main' into simplify_matrix_calculations 2022-10-10 02:45:40 +02:00
Felix Dick
3bf7c5aea1 Change matrixProjection function stop use matrixFlip180 everywhere. 2022-10-10 01:35:42 +02:00
Felix Dick
092dbda88a Let openGL transpose the matrixes for us. 2022-10-10 01:32:04 +02:00
vaxerski
cb687c208c [gha] bump flake inputs 2022-10-09 20:30:56 +00:00
vaxerski
945b4d7139 update wlroots dep 2022-10-09 21:29:54 +01:00
vaxerski
881f828250 better subsurface handling on unmaps 2022-10-09 17:40:30 +01:00
vaxerski
0743dab3f0 use popup base surface instead of subsurface for addPopupGlobalCoords 2022-10-09 17:10:20 +01:00
vaxerski
496e37d044 ensure texture safety in clearWithTex() 2022-10-09 17:02:39 +01:00
Vaxry
1263bd5dcb Merge pull request #817 from Dickby/transform_box_in_renderRectWithDamage
inverse_transform the box in renderRectWithDamage.
2022-10-09 09:46:22 +01:00
Felix Dick
9ee78b1a92 inverse_transform the box in renderRectWithDamage. 2022-10-09 01:58:00 +02:00
Histausse
406b2fe6dc Add additionnal matrices and rename config var 2022-10-09 00:45:34 +02:00
vaxerski
90f2259f5e [gha] bump flake inputs 2022-10-08 17:01:31 +00:00
vaxerski
948f4978e7 update wlroots dep 2022-10-08 18:00:20 +01:00
Histausse
32ae0c51f0 Add input:touchdevice:td_rotation config
Add support for touch device roation. The rotation is
set globally with `input:touchdevice:td_rotation config` and by
device with `td_rotation` in a device block.
2022-10-08 15:25:46 +02:00
Vaxry
fe4a97f245 Merge pull request #794 from Dickby/pixman_early_outs
Check earlier if pixman_region is empty in some places.
2022-10-08 12:00:17 +01:00
Felix Dick
2f3528c076 Check earlier if pixman regions are empty. 2022-10-08 11:20:04 +02:00
vaxerski
1964bcb13f add open/close layer events 2022-10-07 22:25:00 +01:00
Vaxry
4b779ac142 Merge pull request #811 from Dickby/add_missing_pixman_region32_fini
Add missing pixman_region32_fini.
2022-10-07 22:20:35 +01:00
vaxerski
abc2d442dd fix a VRAM leak in destroyMonitorResources 2022-10-07 22:19:23 +01:00
Felix Dick
b64f1fc5c4 Add missing pixman_region32_fini. 2022-10-07 23:11:20 +02:00
vaxerski
33d264eaa7 release all fbs in destroyMonitorResources 2022-10-07 21:13:28 +01:00
Vaxry
5e3b8c3233 Merge pull request #807 from Dickby/fix_monitor_transforms
Transform the box data send to texture shaders.
2022-10-07 20:12:28 +01:00
Felix Dick
bbdfb7853d Transform the box data send to texture shaders. 2022-10-07 20:55:41 +02:00
vaxerski
a19b152e4a make swipe respect slidevert 2022-10-07 16:52:53 +01:00
vaxerski
1468001d3b offset floating windows out of bounds on ws anims 2022-10-07 12:34:54 +01:00
vaxerski
7faa3c367d Added clipping support, clip windows on slide anim 2022-10-07 10:43:51 +01:00
vaxerski
fd379db846 swallow improvements 2022-10-07 09:46:01 +01:00
vaxerski
28a6e0ce31 [gha] bump flake inputs 2022-10-06 21:09:10 +00:00
vaxerski
af7d60b3f8 revert wlroots ver to fix critical gpu issue 2022-10-06 22:08:08 +01:00
Vaxry
c4487534d2 Merge pull request #801 from fufexan/scrollfactor
Add input:touchpad:scroll_factor
2022-10-06 21:26:11 +01:00
Mihai Fufezan
e4820d1c71 Add input:touchpad:scroll_factor 2022-10-06 22:47:05 +03:00
vaxerski
b4a8efc1a7 fix naming when workspace back and forth 2022-10-06 20:40:58 +01:00
vaxerski
9480c0fb90 fix workspace previous with multi-mon ws moves 2022-10-06 20:18:49 +01:00
vaxerski
f901c60da5 return true on vt switch keysyms to avoid printing stuff 2022-10-06 19:31:32 +01:00
vaxerski
922e978f56 reset sigmask on fork 2022-10-06 19:02:03 +01:00
vaxerski
0508c7d384 more monitor checks for shutdown: 2022-10-06 18:43:50 +01:00
vaxerski
ee3b770cfd more checks in pid gathering 2022-10-06 17:58:38 +01:00
Vaxry
a29af89545 Merge pull request #793 from Dickby/fix_compiler_warnings
Fix compiler warnings.
2022-10-06 12:54:04 +01:00
Felix Dick
552c4b7361 Fix compiler warnings. 2022-10-06 13:42:52 +02:00
vaxerski
d7ef19e2e7 map touch to the correct output 2022-10-06 09:26:05 +01:00
vaxerski
190ddb5697 added a noanim rule 2022-10-06 09:16:40 +01:00
vaxerski
095688712d add minsize rule 2022-10-06 09:09:58 +01:00
vaxerski
d264fbd36a fix string corruption in hyprctl monitors -j 2022-10-06 09:04:46 +01:00
vaxerski
e4527c6b60 use goalv in clientsRequest 2022-10-06 08:54:09 +01:00
Vaxry
32e8eda40a Merge pull request #787 from fufexan/libinput
Add accel profile and scroll method
2022-10-05 21:58:40 +01:00
Mihai Fufezan
477ad2dd82 Add accel profile and scroll method 2022-10-05 23:51:08 +03:00
vaxerski
e90c5c6347 fix tty switch freeze 2022-10-05 21:41:27 +01:00
vaxerski
11ce468996 add dpms status info in hyprctl 2022-10-05 18:14:11 +01:00
vaxerski
9c5023ab1a monitor desc improvements 2022-10-05 17:38:36 +01:00
vaxerski
0e4a894edb add dpms per output 2022-10-05 10:31:47 +01:00
vaxerski
71e2562a41 add desc: to monitor rules 2022-10-05 10:22:33 +01:00
Vaxry
9153a81090 Merge pull request #781 from Dickby/fix_left_handed
Fix getDeviceInt string arg "input:left_handed"
2022-10-05 08:06:38 +01:00
Felix Dick
0d7f6eac9e Merge branch 'make_TTY_unsigned' into fix_left_handed 2022-10-05 04:51:48 +02:00
Felix Dick
6d46ed4011 Fix getDeviceInt string arg "input:left_handed" 2022-10-05 04:25:26 +02:00
Felix Dick
f825b87c2a Fix compiler warnig comparing signed and unsigned integers. 2022-10-05 02:42:51 +02:00
vaxerski
44da575ea8 [gha] bump flake inputs 2022-10-04 22:25:26 +00:00
vaxerski
a587909fd5 update wlroots dep 2022-10-04 23:24:31 +01:00
vaxerski
fd81ba5a4f [gha] bump flake inputs 2022-10-04 22:22:12 +00:00
Vaxry
934f81c93d Merge pull request #777 from Dickby/fix_shader_error
Remove texcoord from QUADFRAGSRC.
2022-10-04 23:20:52 +01:00
Felix Dick
e8be1507ef Remove texcoord from QUADFRAGSRC.
texcoord is unused in the rounding part of the textureshaders.
QUADFRAGSRC isn't using that variable inside the non rounding code.
Because of that opengl optimizes that variable out, and is complaining
if glGetAttribLocation is called on it.
2022-10-05 00:04:32 +02:00
vaxerski
60c414ccad add left_handed config for input 2022-10-04 21:46:41 +01:00
vaxerski
0d702b556d Add switch device handling and binds 2022-10-04 20:07:21 +01:00
vaxerski
9bbae5b8e2 ignore VT switches to current vt 2022-10-04 16:53:09 +01:00
vaxerski
719a5b4f0b use vectorToWindowIdeal in mouse binds 2022-10-04 16:08:55 +01:00
Vaxry
7bdfdaa28a Merge pull request #742 from Dickby/rework_rounding_shader
Rework rounding shader
2022-10-04 14:17:16 +01:00
vaxerski
a80e0cecfe fixes to window swallowing with same pid 2022-10-04 11:16:49 +01:00
vaxerski
3e3f6aef5e additional logic for identical pid swallowing 2022-10-04 10:17:10 +01:00
Vaxry
996938b7e7 Merge pull request #773 from lylac-1/main
focusedmon event check change
2022-10-04 10:04:10 +01:00
lylac
f9325b1655 focusedmon event check change
Compare PLASTWINDOW & PWINDOWTOCHANGETO m_iMonitorID's instead of PWINDOWTOCHANGETO->m_iMonitorID & g_pCompositor->m_pLastMonitor->ID
2022-10-04 18:19:14 +13:00
vaxerski
63dfe305dd log GPU info for debugging 2022-10-03 23:10:15 +01:00
Mihai Fufezan
ec0c6fa22a Nix & meson: 0.14.0 -> 0.15.0 2022-10-04 00:51:49 +03:00
Felix Dick
c6333ba796 Remove unused ignoreCorners variable from texture shaders. 2022-10-01 03:30:58 +02:00
Felix Dick
6fe103cf06 Cut the number of pixels that call length() in half. 2022-10-01 03:14:13 +02:00
Felix Dick
71733f68ef Merge branch 'fix_rounding_in_size_changing_windows' into rework_rounding_shader 2022-10-01 01:35:13 +02:00
Felix Dick
d867d42366 Merge branch 'main' into fix_rounding_in_size_changing_windows 2022-09-30 01:38:50 +02:00
Felix Dick
6eb7d00386 Send absolute screen coordinates to texture shaders. 2022-09-29 23:19:56 +02:00
Felix Dick
09268d756f Merge branch 'main' into rework_rounding_shader 2022-09-29 21:15:08 +02:00
Felix Dick
e5dced8b3f Merge branch 'main' into fix_rounding_in_size_changing_windows 2022-09-29 21:13:48 +02:00
Felix Dick
b38e7b596f Don't pass bottomRight to textureShaders compute it within. 2022-09-29 21:10:05 +02:00
Felix Dick
1424539e4d Merge branch 'main' into rework_rounding_shader 2022-09-29 20:41:39 +02:00
Felix Dick
425b07d1e5 Merge branch 'main' into rework_rounding_shader 2022-09-29 14:24:59 +02:00
Felix Dick
65fb526d5c Even less branching (taken more or less from the border shader). 2022-09-29 06:56:17 +02:00
Felix Dick
0549aa193f fixing your shit. 2022-09-28 23:33:18 +02:00
Felix Dick
168a326609 Merge branch 'main' into rework_rounding_shader 2022-09-28 23:11:11 +02:00
Felix Dick
7edbaea23d Make the rounding texture shaders smaller and more efficient. 2022-09-28 18:40:04 +02:00
Felix Dick
5ff44467d7 Avoid 38 files to compile every time a shader is modified. 2022-09-28 14:48:05 +02:00
98 changed files with 6264 additions and 1787 deletions

View File

@@ -41,7 +41,7 @@ jobs:
cp ./LICENSE hyprland/ cp ./LICENSE hyprland/
cp build/Hyprland hyprland/ cp build/Hyprland hyprland/
cp hyprctl/hyprctl hyprland/ cp hyprctl/hyprctl hyprland/
cp subprojects/wlroots/build/libwlroots.so.11032 hyprland/ cp subprojects/wlroots/build/libwlroots.so.12032 hyprland/
cp build/Hyprland hyprland/ cp build/Hyprland hyprland/
cp -r example/ hyprland/ cp -r example/ hyprland/
cp -r assets/ hyprland/ cp -r assets/ hyprland/
@@ -62,7 +62,7 @@ jobs:
run: | run: |
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
pacman --noconfirm --noprogressbar -Syyu pacman --noconfirm --noprogressbar -Syyu
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd cmake
- name: Checkout Hyprland - name: Checkout Hyprland
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
@@ -73,13 +73,23 @@ jobs:
-Ddefault_library=static -Ddefault_library=static
- name: Compile - name: Compile
run: ninja -C obj-x86_64-pc-linux-gnu run: ninja -C obj-x86_64-pc-linux-gnu
# - name: Compress artifacts
# run: | noxwayland:
# mkdir x86_64-pc-linux-gnu name: "Build Hyprland in pure Wayland (Arch)"
# DESTDIR=$PWD/x86_64-pc-linux-gnu meson install -C obj-x86_64-pc-linux-gnu --tags runtime runs-on: ubuntu-latest
# tar -cvf x86_64-pc-linux-gnu.tar.xz x86_64-pc-linux-gnu container:
# - name: Upload artifacts image: archlinux
# uses: actions/upload-artifact@v3 steps:
# with: - name: Download dependencies
# name: Build artifacts (x86_64-pc-linux-gnu) run: |
# path: x86_64-pc-linux-gnu.tar.xz sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
pacman --noconfirm --noprogressbar -Syyu
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd
- name: Checkout Hyprland
uses: actions/checkout@v3
with:
submodules: true
- name: Configure
run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja
- name: Compile
run: make config && make release

View File

@@ -16,13 +16,13 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: Install nix - name: Install nix
uses: cachix/install-nix-action@v17 uses: cachix/install-nix-action@v18
with: with:
install_url: https://releases.nixos.org/nix/nix-2.10.3/install install_url: https://nixos.org/nix/install
extra_nix_config: | extra_nix_config: |
auto-optimise-store = true auto-optimise-store = true
experimental-features = nix-command flakes experimental-features = nix-command flakes
- uses: cachix/cachix-action@v10 - uses: cachix/cachix-action@v12
with: with:
name: hyprland name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

View File

@@ -9,9 +9,9 @@ jobs:
- name: Clone repository - name: Clone repository
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install nix - name: Install nix
uses: cachix/install-nix-action@v17 uses: cachix/install-nix-action@v18
with: with:
install_url: https://releases.nixos.org/nix/nix-2.8.0/install install_url: https://nixos.org/nix/install
extra_nix_config: | extra_nix_config: |
auto-optimise-store = true auto-optimise-store = true
experimental-features = nix-command flakes experimental-features = nix-command flakes

View File

@@ -17,7 +17,7 @@ jobs:
- name: Create tarball with submodules - name: Create tarball with submodules
id: tar id: tar
run: tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz * run: mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
- id: whatrelease - id: whatrelease
name: Get latest release name: Get latest release

2
.gitignore vendored
View File

@@ -25,3 +25,5 @@ hyprctl/hyprctl
gmon.out gmon.out
*.out *.out
*.tar.gz *.tar.gz
PKGBUILD

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "wlroots"] [submodule "wlroots"]
path = subprojects/wlroots path = subprojects/wlroots
url = https://gitlab.freedesktop.org/wlroots/wlroots.git url = https://gitlab.freedesktop.org/wlroots/wlroots.git
[submodule "subprojects/hyprland-protocols"]
path = subprojects/hyprland-protocols
url = https://github.com/hyprwm/hyprland-protocols

View File

@@ -5,7 +5,7 @@ project(Hyprland
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
message(STATUS "Configuring Hyprland!") message(STATUS "Gathering git info")
# Get git info # Get git info
# hash and branch # hash and branch
@@ -22,27 +22,39 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE) OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process( execute_process(
COMMAND bash -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1" COMMAND sh -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g'"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_MESSAGE OUTPUT_VARIABLE GIT_COMMIT_MESSAGE
OUTPUT_STRIP_TRAILING_WHITESPACE) OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process( execute_process(
COMMAND bash -c "git diff-index --quiet HEAD -- || echo \"dirty\"" COMMAND sh -c "git diff-index --quiet HEAD -- || echo \"dirty\""
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DIRTY OUTPUT_VARIABLE GIT_DIRTY
OUTPUT_STRIP_TRAILING_WHITESPACE) OUTPUT_STRIP_TRAILING_WHITESPACE)
# #
# #
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Configuring Hyprland in Debug with CMake")
add_definitions( -DHYPRLAND_DEBUG )
ELSE()
add_compile_options( -O3 )
message(STATUS "Configuring Hyprland in Release with CMake")
ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
include_directories(. PRIVATE "subprojects/wlroots/include/") include_directories(. PRIVATE "subprojects/wlroots/include/")
include_directories(. PRIVATE "subprojects/wlroots/build/include/") include_directories(. PRIVATE "subprojects/wlroots/build/include/")
add_compile_options(-std=c++23 -DWLR_USE_UNSTABLE ) set(CMAKE_CXX_STANDARD 23)
add_compile_options(-DWLR_USE_UNSTABLE)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing) add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing)
message(STATUS "Checking deps...")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo libdrm egl xkbcommon libinput xcb) # we do not check for wlroots, as we provide it ourselves pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo libdrm egl xkbcommon libinput) # we do not check for wlroots, as we provide it ourselves
file(GLOB_RECURSE SRCFILES "src/*.cpp") file(GLOB_RECURSE SRCFILES "src/*.cpp")
@@ -56,15 +68,11 @@ ENDIF(LEGACY_RENDERER MATCHES true)
IF(NO_XWAYLAND MATCHES true) IF(NO_XWAYLAND MATCHES true)
message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!") message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
add_definitions( -DNO_XWAYLAND ) add_definitions( -DNO_XWAYLAND )
ENDIF(NO_XWAYLAND MATCHES true)
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Configuring Hyprland in Debug with CMake!")
add_definitions( -DHYPRLAND_DEBUG )
ELSE() ELSE()
add_compile_options( -O3 ) message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
message(STATUS "Configuring Hyprland in Release with CMake!") pkg_check_modules(xcbdep REQUIRED xcb)
ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) target_link_libraries(Hyprland xcb)
ENDIF(NO_XWAYLAND MATCHES true)
target_compile_definitions(Hyprland PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"") target_compile_definitions(Hyprland PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
target_compile_definitions(Hyprland PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"") target_compile_definitions(Hyprland PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"")
@@ -77,20 +85,28 @@ set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack) include(CPack)
message(STATUS "Setting link libraries")
target_link_libraries(Hyprland PkgConfig::deps) target_link_libraries(Hyprland PkgConfig::deps)
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Setting debug flags")
target_link_libraries(Hyprland asan)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg -no-pie -fno-builtin -fsanitize=address")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg -no-pie -fno-builtin")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg -no-pie -fno-builtin")
ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
target_link_libraries(Hyprland target_link_libraries(Hyprland
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.11032 # wlroots is provided by us ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032 # wlroots is provided by us
pixman-1 pixman-1
OpenGL OpenGL
GLESv2 GLESv2
pthread pthread
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
${CMAKE_SOURCE_DIR}/ext-workspace-unstable-v1-protocol.o ${CMAKE_SOURCE_DIR}/ext-workspace-unstable-v1-protocol.o
${CMAKE_SOURCE_DIR}/wlr-foreign-toplevel-management-unstable-v1-protocol.o
${CMAKE_SOURCE_DIR}/hyprland-toplevel-export-v1-protocol.o
) )
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg -no-pie -fno-builtin")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg -no-pie -fno-builtin")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg -no-pie -fno-builtin")
ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)

View File

@@ -91,21 +91,51 @@ wlr-output-power-management-unstable-v1-protocol.c:
wlr-output-power-management-unstable-v1-protocol.o: wlr-output-power-management-unstable-v1-protocol.h wlr-output-power-management-unstable-v1-protocol.o: wlr-output-power-management-unstable-v1-protocol.h
hyprland-toplevel-export-v1-protocol.h:
$(WAYLAND_SCANNER) server-header \
subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml $@
hyprland-toplevel-export-v1-protocol.c:
$(WAYLAND_SCANNER) private-code \
subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml $@
hyprland-toplevel-export-v1-protocol.o: hyprland-toplevel-export-v1-protocol.h
linux-dmabuf-unstable-v1-protocol.h:
$(WAYLAND_SCANNER) server-header \
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
linux-dmabuf-unstable-v1-protocol.c:
$(WAYLAND_SCANNER) private-code \
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
linux-dmabuf-unstable-v1-protocol.o: linux-dmabuf-unstable-v1-protocol.h
wlr-foreign-toplevel-management-unstable-v1-protocol.h:
$(WAYLAND_SCANNER) server-header \
protocols/wlr-foreign-toplevel-management-unstable-v1.xml $@
wlr-foreign-toplevel-management-unstable-v1-protocol.c:
$(WAYLAND_SCANNER) private-code \
protocols/wlr-foreign-toplevel-management-unstable-v1.xml $@
wlr-foreign-toplevel-management-unstable-v1-protocol.o: wlr-foreign-toplevel-management-unstable-v1-protocol.h
legacyrenderer: legacyrenderer:
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:STRING=true -H./ -B./build -G Ninja 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 $(nproc) cmake --build ./build --config Release --target all -j$(shell nproc)
legacyrendererdebug: legacyrendererdebug:
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:STRING=true -H./ -B./build -G Ninja mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:STRING=true -H./ -B./build -G Ninja
cmake --build ./build --config Release --target all -j $(nproc) cmake --build ./build --config Release --target all -j$(shell nproc)
release: release:
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -H./ -B./build -G Ninja mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -H./ -B./build -G Ninja
cmake --build ./build --config Release --target all -j $(nproc) cmake --build ./build --config Release --target all -j$(shell nproc)
debug: debug:
mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -H./ -B./build -G Ninja mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -H./ -B./build -G Ninja
cmake --build ./build --config Debug --target all -j $(nproc) cmake --build ./build --config Debug --target all -j$(shell nproc)
clear: clear:
rm -rf build rm -rf build
@@ -114,14 +144,17 @@ clear:
rm -rf ./subprojects/wlroots/build rm -rf ./subprojects/wlroots/build
all: all:
make config make clear
make fixwlr
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 /usr/lib/ && cd ../..
make protocols
make release make release
cd ./hyprctl && make all && cd .. cd hyprctl && make all && cd ..
install: install:
make clear make clear
make fixwlr make fixwlr
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../.. cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 /usr/lib/ && cd ../..
make protocols make protocols
make release make release
cd hyprctl && make all && cd .. cd hyprctl && make all && cd ..
@@ -141,7 +174,7 @@ install:
cleaninstall: cleaninstall:
make clear make clear
make fixwlr make fixwlr
cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.11032 /usr/lib/ && cd ../.. cd ./subprojects/wlroots && meson build/ --buildtype=release && ninja -C build/ && cp ./build/libwlroots.so.12032 /usr/lib/ && cd ../..
make protocols make protocols
make release make release
cd hyprctl && make all && cd .. cd hyprctl && make all && cd ..
@@ -161,15 +194,15 @@ uninstall:
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
rm -f ${PREFIX}/bin/Hyprland rm -f ${PREFIX}/bin/Hyprland
rm -f ${PREFIX}/bin/hyprctl rm -f ${PREFIX}/bin/hyprctl
rm -f /usr/lib/libwlroots.so.11032 rm -f /usr/lib/libwlroots.so.12032
rm -rf ${PREFIX}/share/hyprland rm -rf ${PREFIX}/share/hyprland
rm -f ${PREFIX}/share/man/man1/Hyprland.1 rm -f ${PREFIX}/share/man/man1/Hyprland.1
rm -f ${PREFIX}/share/man/man1/hyprctl.1 rm -f ${PREFIX}/share/man/man1/hyprctl.1
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o linux-dmabuf-unstable-v1-protocol.o hyprland-toplevel-export-v1-protocol.o wlr-foreign-toplevel-management-unstable-v1-protocol.o
fixwlr: fixwlr:
sed -i -E 's/(soversion = 11)([^032]|$$)/soversion = 11032/g' subprojects/wlroots/meson.build sed -i -E 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
rm -rf ./subprojects/wlroots/build rm -rf ./subprojects/wlroots/build
@@ -178,7 +211,7 @@ config:
make fixwlr make fixwlr
cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release -Dwerror=false -Dexamples=false
cd subprojects/wlroots && ninja -C build/ cd subprojects/wlroots && ninja -C build/
cd subprojects/wlroots && ninja -C build/ install cd subprojects/wlroots && ninja -C build/ install

View File

@@ -6,7 +6,6 @@
![Badge Workflow] ![Badge Workflow]
[![Badge License]][License] [![Badge License]][License]
![Badge Lines]
![Badge Language] ![Badge Language]
[![Badge Pull Requests]][Pull Requests] [![Badge Pull Requests]][Pull Requests]
[![Badge Issues]][Issues] [![Badge Issues]][Issues]
@@ -40,31 +39,28 @@ Hyprland is still in pretty early development compared to some other Wayland com
Although Hyprland is pretty stable, it may have some bugs. Although Hyprland is pretty stable, it may have some bugs.
### Help Wanted
Hyprland needs testers! <br/>
Try it out and report bugs / suggestions!
# Features # Features
- Easily expandable and readable codebase - Easily expandable and readable codebase
- Config reloaded instantly upon saving - Config reloaded instantly upon saving
- Custom bezier curve based animations - Custom bezier curve based animations
- `wlr_ext` workspaces protocol support
- Dual Kawase blur - Dual Kawase blur
- Drop shadows - Drop shadows
- Rounded corners
- Gradient borders
- Fully dynamic workspaces - Fully dynamic workspaces
- Closely follows `wlroots-git` - Closely follows `wlroots-git`
- Global keybinds passed to your apps of choice - Global keybinds passed to your apps of choice
- A lot of customization
- Bundled wlroots - Bundled wlroots
- Window/layer fade in/out - Window/layer fade in/out
- Tiling/pseudotiling/floating/fullscreen windows - Tiling/pseudotiling/floating/fullscreen windows
- Switching workspaces between window modes on the fly - Switching workspaces between window modes on the fly
- Special workspace (scratchpad) - Special workspaces (scratchpads)
- Window/monitor rules - Window/monitor rules
- Socket-based IPC - Socket-based IPC
- `wlr_ext` workspaces protocol support
- Event system for bash scripts - Event system for bash scripts
- Rounded corners
- Full damage tracking - Full damage tracking
- Docks support - Docks support
- Drawing tablet support - Drawing tablet support
@@ -150,9 +146,9 @@ Try it out and report bugs / suggestions!
<!----------------------------------{ Images }---------------------------------> <!----------------------------------{ Images }--------------------------------->
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg [Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
[Preview A]: https://i.imgur.com/pC6YF1Y.png [Preview A]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
[Preview B]: https://i.imgur.com/NbrTnZH.png [Preview B]: https://i.imgur.com/pC6YF1Y.png
[Preview C]: https://i.imgur.com/sCafdKQ.png [Preview C]: https://i.imgur.com/NbrTnZH.png
<!----------------------------------{ Badges }---------------------------------> <!----------------------------------{ Badges }--------------------------------->

View File

@@ -1,10 +1,10 @@
.\" Automatically generated by Pandoc 2.5 .\" Automatically generated by Pandoc 2.9.2.1
.\" .\"
.TH "Hyprland" "1" "24 Aug 2022" "" "Hyprland User Manual" .TH "Hyprland" "1" "02 Dec 2022" "" "Hyprland User Manual"
.hy .hy
.SH NAME .SH NAME
.PP .PP
Hyprland \- Dynamic tiling Wayland compositor Hyprland - Dynamic tiling Wayland compositor
.SH SYNOPSIS .SH SYNOPSIS
.PP .PP
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]]. \f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
@@ -27,14 +27,14 @@ For configuration information please see
<\f[I]https://github.com/hyprwm/Hyprland/wiki\f[R]>. <\f[I]https://github.com/hyprwm/Hyprland/wiki\f[R]>.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \f[B]\-h\f[R], \f[B]\-\-help\f[R] \f[B]-h\f[R], \f[B]--help\f[R]
Show command usage. Show command usage.
.TP .TP
.B \f[B]\-c\f[R], \f[B]\-\-config\f[R] \f[B]-c\f[R], \f[B]--config\f[R]
Specify config file to use. Specify config file to use.
.SH BUGS .SH BUGS
.TP .TP
.B Submit bug reports and request features online at: Submit bug reports and request features online at:
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]> <\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
.SH SEE ALSO .SH SEE ALSO
.PP .PP

View File

@@ -57,3 +57,15 @@ coredumpctl info [PID]
``` ```
where `[PID]` is the PID you remembered. where `[PID]` is the PID you remembered.
## Obtaining the debug Hyprland coredump
In very rare cases, the normal coredump would not be enough.
If that's the case, you could try obtaining the debug coredump.
1. [Compile Hyprland with debug mode](http://wiki.hyprland.org/Contributing-and-Debugging/#build-in-debug-mode)
> Note: The config file used will be `hyprlandd.conf` instead of `hyprland.conf`
2. Reproduce the crash in debug mode.
3. `env DEBUGINFOD_URLS="https://debuginfod.archlinux.org/" coredumpctl debug [PID]`(see section above)
4. Wait until the `(gdb)` appears
5. If gdb asks you `press y to continue without paging?` Type `y`
6. `bt -full`
7. copy the output of the command and provide that.

View File

@@ -1,10 +1,10 @@
.\" Automatically generated by Pandoc 2.5 .\" Automatically generated by Pandoc 2.9.2.1
.\" .\"
.TH "hyprctl" "1" "24 Aug 2022" "" "hyprctl User Manual" .TH "hyprctl" "1" "02 Dec 2022" "" "hyprctl User Manual"
.hy .hy
.SH NAME .SH NAME
.PP .PP
hyprctl \- Utility for controlling parts of Hyprland from a CLI or a hyprctl - Utility for controlling parts of Hyprland from a CLI or a
script script
.SH SYNOPSIS .SH SYNOPSIS
.PP .PP
@@ -26,7 +26,7 @@ For dispatchers without parameters it can be anything.
.PP .PP
Returns: \f[I]ok\f[R] on success, and an error message on failure. Returns: \f[I]ok\f[R] on success, and an error message on failure.
.TP .TP
.B Examples: Examples:
\f[B]hyprctl\f[R] \f[I]dispatch exec kitty\f[R] \f[B]hyprctl\f[R] \f[I]dispatch exec kitty\f[R]
.RS .RS
.PP .PP
@@ -41,7 +41,7 @@ Set a config keyword dynamically.
.PP .PP
Returns: \f[I]ok\f[R] on success, and an error message on failure. Returns: \f[I]ok\f[R] on success, and an error message on failure.
.TP .TP
.B Examples: Examples:
\f[B]hyprctl\f[R] \f[I]keyword bind SUPER,0,pseudo\f[R] \f[B]hyprctl\f[R] \f[I]keyword bind SUPER,0,pseudo\f[R]
.RS .RS
.PP .PP
@@ -112,13 +112,13 @@ Returns the current random splash.
.RE .RE
.SH OPTIONS .SH OPTIONS
.PP .PP
\f[B]\-\-batch\f[R] \f[B]--batch\f[R]
.RS .RS
.PP .PP
Specify a batch of commands to execute. Specify a batch of commands to execute.
.TP .TP
.B Example: Example:
\f[B]hyprctl\f[R] \f[I]\-\-batch \[dq]keyword general:border_size 2 ; \f[B]hyprctl\f[R] \f[I]--batch \[dq]keyword general:border_size 2 ;
keyword general:gaps_out 20\[dq]\f[R] keyword general:gaps_out 20\[dq]\f[R]
.RS .RS
.PP .PP
@@ -126,14 +126,14 @@ keyword general:gaps_out 20\[dq]\f[R]
.RE .RE
.RE .RE
.PP .PP
\f[B]\-j\f[R] \f[B]-j\f[R]
.RS .RS
.PP .PP
Outputs information in JSON. Outputs information in JSON.
.RE .RE
.SH BUGS .SH BUGS
.TP .TP
.B Submit bug reports and request features online at: Submit bug reports and request features online at:
<\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]> <\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
.SH SEE ALSO .SH SEE ALSO
.PP .PP

View File

@@ -1,117 +1,158 @@
# This is an example Hyprland config file. # This is an example Hyprland config file.
# Syntax is the same as in Hypr, but settings might differ.
# #
# Refer to the wiki for more information. # Refer to the wiki for more information.
# #
# Please note not all available settings / options are set here. # Please note not all available settings / options are set here.
# For a full list, see the wiki (basic and advanced configuring) # For a full list, see the wiki
# #
# See https://wiki.hyprland.org/Configuring/Monitors/
monitor=,preferred,auto,1 monitor=,preferred,auto,1
workspace=DP-1,1
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
# Execute your favorite apps at launch
# exec-once = waybar & hyprpaper & firefox
# Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
input { input {
kb_file= kb_layout = us
kb_layout= kb_variant =
kb_variant= kb_model =
kb_model= kb_options =
kb_options= kb_rules =
kb_rules=
follow_mouse=1 follow_mouse = 1
touchpad { touchpad {
natural_scroll=no natural_scroll = no
} }
sensitivity=0 # -1.0 - 1.0, 0 means no modification. sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
} }
general { general {
gaps_in=5 # See https://wiki.hyprland.org/Configuring/Variables/ for more
gaps_out=20
border_size=2
col.active_border=0x66ee1111
col.inactive_border=0x66333333
apply_sens_to_raw=0 # whether to apply the sensitivity to raw input (e.g. used by games where you aim using your mouse) gaps_in = 5
gaps_out = 20
border_size = 2
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
col.inactive_border = rgba(595959aa)
damage_tracking=full # leave it on full unless you hate your GPU and want to make it suffer layout = dwindle
} }
decoration { decoration {
rounding=10 # See https://wiki.hyprland.org/Configuring/Variables/ for more
blur=1
blur_size=3 # minimum 1 rounding = 10
blur_passes=1 # minimum 1 blur = yes
blur_new_optimizations=1 blur_size = 3
blur_passes = 1
blur_new_optimizations = on
drop_shadow = yes
shadow_range = 4
shadow_render_power = 3
col.shadow = rgba(1a1a1aee)
} }
animations { animations {
enabled=1 enabled = yes
animation=windows,1,7,default
animation=border,1,10,default # Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
animation=fade,1,10,default
animation=workspaces,1,6,default bezier = myBezier, 0.05, 0.9, 0.1, 1.05
animation = windows, 1, 7, myBezier
animation = windowsOut, 1, 7, default, popin 80%
animation = border, 1, 10, default
animation = fade, 1, 7, default
animation = workspaces, 1, 6, default
} }
dwindle { dwindle {
pseudotile=0 # enable pseudotiling on dwindle # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
pseudotile = yes # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = yes # you probably want this
}
master {
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
new_is_master = true
} }
gestures { gestures {
workspace_swipe=no # See https://wiki.hyprland.org/Configuring/Variables/ for more
workspace_swipe = off
} }
# example window rules # Example per-device config
# for windows named/classed as abc and xyz # See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
#windowrule=move 69 420,abc device:epic mouse V1 {
#windowrule=size 420 69,abc sensitivity = -0.5
#windowrule=tile,xyz }
#windowrule=float,abc
#windowrule=pseudo,abc
#windowrule=monitor 0,xyz
# some nice mouse binds # Example windowrule v1
bindm=SUPER,mouse:272,movewindow # windowrule = float, ^(kitty)$
bindm=SUPER,mouse:273,resizewindow # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# example binds
bind=SUPER,Q,exec,kitty
bind=SUPER,C,killactive,
bind=SUPER,M,exit,
bind=SUPER,E,exec,dolphin
bind=SUPER,V,togglefloating,
bind=SUPER,R,exec,wofi --show drun -o DP-3
bind=SUPER,P,pseudo,
bind=SUPER,left,movefocus,l # See https://wiki.hyprland.org/Configuring/Keywords/ for more
bind=SUPER,right,movefocus,r $mainMod = SUPER
bind=SUPER,up,movefocus,u
bind=SUPER,down,movefocus,d
bind=SUPER,1,workspace,1 # Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind=SUPER,2,workspace,2 bind = $mainMod, Q, exec, kitty
bind=SUPER,3,workspace,3 bind = $mainMod, C, killactive,
bind=SUPER,4,workspace,4 bind = $mainMod, M, exit,
bind=SUPER,5,workspace,5 bind = $mainMod, E, exec, dolphin
bind=SUPER,6,workspace,6 bind = $mainMod, V, togglefloating,
bind=SUPER,7,workspace,7 bind = $mainMod, R, exec, wofi --show drun
bind=SUPER,8,workspace,8 bind = $mainMod, P, pseudo, # dwindle
bind=SUPER,9,workspace,9 bind = $mainMod, J, togglesplit, # dwindle
bind=SUPER,0,workspace,10
bind=ALT,1,movetoworkspace,1 # Move focus with mainMod + arrow keys
bind=ALT,2,movetoworkspace,2 bind = $mainMod, left, movefocus, l
bind=ALT,3,movetoworkspace,3 bind = $mainMod, right, movefocus, r
bind=ALT,4,movetoworkspace,4 bind = $mainMod, up, movefocus, u
bind=ALT,5,movetoworkspace,5 bind = $mainMod, down, movefocus, d
bind=ALT,6,movetoworkspace,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 # Switch workspaces with mainMod + [0-9]
bind=SUPER,mouse_up,workspace,e-1 bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
# Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1
# Move/resize windows with mainMod + LMB/RMB and dragging
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow

16
example/screenShader.frag Normal file
View File

@@ -0,0 +1,16 @@
//
// Example blue light filter shader.
//
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D tex;
void main() {
vec4 pixColor = texture2D(tex, v_texcoord);
pixColor[2] *= 0.8;
gl_FragColor = pixColor;
}

69
flake.lock generated
View File

@@ -1,12 +1,44 @@
{ {
"nodes": { "nodes": {
"hyprland-protocols": {
"flake": false,
"locked": {
"lastModified": 1670703428,
"narHash": "sha256-4KUW5SKR0Y9uaYGcYwy53YJ3B/sgiprCL4fRGO+mpOA=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "d0d6db8cb5bef6d93ca3ad8fb2124964173396da",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-protocols",
"type": "github"
}
},
"hyprland-protocols_2": {
"flake": false,
"locked": {
"lastModified": 1670185345,
"narHash": "sha256-hxWGqlPecqEsE6nOHDV29KFBKePbY2Ipeac6lrChMKY=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "4623a404c091e64743ba310199bb380ec52f1936",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-protocols",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1664687381, "lastModified": 1670064435,
"narHash": "sha256-9czSuDzS+OGGwq2kC4KXBLXWfYaup+oLB+AA1Md25U4=", "narHash": "sha256-+ELoY30UN+Pl3Yn7RWRPabykwebsVK/kYE9JsIsUMxQ=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "59d2991d4256cdca1c0cda45d876c80a0fe45c31", "rev": "61a8a98e6d557e6dd7ed0cdb54c3a3e3bbc5e25c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -18,19 +50,21 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"hyprland-protocols": "hyprland-protocols",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"wlroots": "wlroots" "wlroots": "wlroots",
"xdph": "xdph"
} }
}, },
"wlroots": { "wlroots": {
"flake": false, "flake": false,
"locked": { "locked": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"lastModified": 1664816798, "lastModified": 1669925104,
"narHash": "sha256-oLJyFT1Fc4UNNaDSN+EYUAWL4CufCBpuS5AV4Z4XANo=", "narHash": "sha256-xMHfW+/G9MieN/5tXHUA5/ztE8dkE093cNFTEUgcwxI=",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "50cc1ef4d3791d86854dd83c15fff17e5ea1a5b6", "rev": "c8eb24d30e18c165728b8788a10716611c3b633d",
"type": "gitlab" "type": "gitlab"
}, },
"original": { "original": {
@@ -39,6 +73,27 @@
"repo": "wlroots", "repo": "wlroots",
"type": "gitlab" "type": "gitlab"
} }
},
"xdph": {
"inputs": {
"hyprland-protocols": "hyprland-protocols_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1670797151,
"narHash": "sha256-ZFzJHqSXhGCjSeMgqTyJG1KJ2Nlwa+NEN9K4oGhWcjg=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "36ffb6892e14b9c5be6e321b3c47fe286ac256e6",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View File

@@ -7,6 +7,16 @@
url = "gitlab:wlroots/wlroots?host=gitlab.freedesktop.org"; url = "gitlab:wlroots/wlroots?host=gitlab.freedesktop.org";
flake = false; flake = false;
}; };
xdph = {
url = "github:hyprwm/xdg-desktop-portal-hyprland";
inputs.nixpkgs.follows = "nixpkgs";
};
hyprland-protocols = {
url = "github:hyprwm/hyprland-protocols";
flake = false;
};
}; };
outputs = inputs @ { outputs = inputs @ {
@@ -20,35 +30,34 @@
"aarch64-linux" "aarch64-linux"
"x86_64-linux" "x86_64-linux"
]; ];
pkgsFor = genSystems (system: pkgsFor = genSystems (system:
import nixpkgs { import nixpkgs {
inherit system; inherit system;
overlays = [ overlays = [
(_: prev: { (_: prev: {
libdrm = prev.libdrm.overrideAttrs (old: rec { libdrm = prev.libdrm.overrideAttrs (old: rec {
version = "2.4.113"; version = "2.4.114";
src = prev.fetchurl { src = prev.fetchurl {
url = "https://dri.freedesktop.org/${old.pname}/${old.pname}-${version}.tar.xz"; url = "https://dri.freedesktop.org/${old.pname}/${old.pname}-${version}.tar.xz";
sha256 = "sha256-f9frKWf2O+tGBvItUOJ32ZNIDQXvdd2Iqb2OZ3Mj5eE="; sha256 = "sha256-MEnPhDpH0S5e7vvDvjSW14L6CfQjRr8Lfe/j0eWY0CY=";
};
});
wayland-protocols = prev.wayland-protocols.overrideAttrs (old: rec {
version = "1.29";
src = prev.fetchurl {
url = "https://gitlab.freedesktop.org/wayland/${old.pname}/-/releases/${version}/downloads/${old.pname}-${version}.tar.xz";
hash = "sha256-4l6at1rHNnBN3v6S6PmshzC+q29WTbYvetaVu6T/ntg=";
}; };
mesonFlags =
[
"-Dinstall-test-programs=true"
"-Domap=enabled"
"-Dcairo-tests=disabled"
]
++ lib.optionals prev.stdenv.hostPlatform.isAarch [
"-Dtegra=enabled"
"-Detnaviv=enabled"
];
}); });
}) })
]; ];
}); });
mkDate = longDate: (lib.concatStringsSep "-" [ mkDate = longDate: (lib.concatStringsSep "-" [
(__substring 0 4 longDate) (builtins.substring 0 4 longDate)
(__substring 4 2 longDate) (builtins.substring 4 2 longDate)
(__substring 6 2 longDate) (builtins.substring 6 2 longDate)
]); ]);
in { in {
overlays.default = _: prev: rec { overlays.default = _: prev: rec {
@@ -58,8 +67,9 @@
}; };
hyprland = prev.callPackage ./nix/default.nix { hyprland = prev.callPackage ./nix/default.nix {
stdenv = prev.gcc12Stdenv; stdenv = prev.gcc12Stdenv;
version = "0.14.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty"); version = "0.18.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
wlroots = wlroots-hyprland; wlroots = wlroots-hyprland;
inherit (inputs) hyprland-protocols;
}; };
hyprland-debug = hyprland.override {debug = true;}; hyprland-debug = hyprland.override {debug = true;};
hyprland-no-hidpi = hyprland.override {hidpiXWayland = false;}; hyprland-no-hidpi = hyprland.override {hidpiXWayland = false;};
@@ -67,6 +77,10 @@
waybar-hyprland = prev.waybar.overrideAttrs (oldAttrs: { waybar-hyprland = prev.waybar.overrideAttrs (oldAttrs: {
mesonFlags = oldAttrs.mesonFlags ++ ["-Dexperimental=true"]; mesonFlags = oldAttrs.mesonFlags ++ ["-Dexperimental=true"];
}); });
xdg-desktop-portal-hyprland = inputs.xdph.packages.${prev.system}.default.override {
hyprland-share-picker = inputs.xdph.packages.${prev.system}.hyprland-share-picker.override {inherit hyprland;};
};
}; };
packages = genSystems (system: packages = genSystems (system:
@@ -78,6 +92,12 @@
devShells = genSystems (system: { devShells = genSystems (system: {
default = pkgsFor.${system}.mkShell.override {stdenv = pkgsFor.${system}.gcc12Stdenv;} { default = pkgsFor.${system}.mkShell.override {stdenv = pkgsFor.${system}.gcc12Stdenv;} {
name = "hyprland-shell"; name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [
cmake
];
buildInputs = [
self.packages.${system}.wlroots-hyprland
];
inputsFrom = [ inputsFrom = [
self.packages.${system}.wlroots-hyprland self.packages.${system}.wlroots-hyprland
self.packages.${system}.hyprland self.packages.${system}.hyprland
@@ -87,7 +107,7 @@
formatter = genSystems (system: pkgsFor.${system}.alejandra); formatter = genSystems (system: pkgsFor.${system}.alejandra);
nixosModules.default = import ./nix/module.nix self; nixosModules.default = import ./nix/module.nix inputs;
homeManagerModules.default = import ./nix/hm-module.nix self; homeManagerModules.default = import ./nix/hm-module.nix self;
}; };

View File

@@ -36,15 +36,24 @@ commands:
reload reload
setcursor setcursor
getoption getoption
cursorpos
switchxkblayout
flags: flags:
-j -> output in JSON -j -> output in JSON
--batch -> execute a batch of commands, separated by ';' --batch -> execute a batch of commands, separated by ';'
)#"; )#";
void request(std::string arg) { void request(std::string arg, int minArgs = 0) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
if (ARGS < minArgs) {
std::cout << "Not enough arguments, expected at least " << minArgs;
return;
}
if (SERVERSOCKET < 0) { if (SERVERSOCKET < 0) {
std::cout << "Couldn't open a socket (1)"; std::cout << "Couldn't open a socket (1)";
return; return;
@@ -80,6 +89,7 @@ void request(std::string arg) {
return; return;
} }
std::string reply = "";
char buffer[8192] = {0}; char buffer[8192] = {0};
sizeWritten = read(SERVERSOCKET, buffer, 8192); sizeWritten = read(SERVERSOCKET, buffer, 8192);
@@ -89,9 +99,20 @@ void request(std::string arg) {
return; return;
} }
reply += std::string(buffer, sizeWritten);
while (sizeWritten == 8192) {
sizeWritten = read(SERVERSOCKET, buffer, 8192);
if (sizeWritten < 0) {
std::cout << "Couldn't read (5)";
return;
}
reply += std::string(buffer, sizeWritten);
}
close(SERVERSOCKET); close(SERVERSOCKET);
std::cout << std::string(buffer); std::cout << reply;
} }
void requestHyprpaper(std::string arg) { void requestHyprpaper(std::string arg) {
@@ -145,25 +166,31 @@ void requestHyprpaper(std::string arg) {
std::cout << std::string(buffer); std::cout << std::string(buffer);
} }
void dispatchRequest(int argc, char** argv) { int dispatchRequest(int argc, char** argv) {
if (argc < 4) { if (argc < 4) {
std::cout << "dispatch requires 2 params"; std::cout << "Usage: hyprctl dispatch <dispatcher> <arg>\n\
return; Execute a hyprland keybind dispatcher with the given argument";
return 1;
} }
std::string rq = "/dispatch"; std::string rq = "/dispatch";
for(int i = 2; i < argc; i++) for(int i = 2; i < argc; i++) {
if (!strcmp(argv[i], "--"))
continue;
rq += " " + std::string(argv[i]); rq += " " + std::string(argv[i]);
}
request(rq); request(rq);
return 0;
} }
void keywordRequest(int argc, char** argv) { int keywordRequest(int argc, char** argv) {
if (argc < 4) { if (argc < 4) {
std::cout << "keyword requires 2 params"; std::cout << "Usage: hyprctl keyword <keyword> <arg>\n\
return; Execute a hyprland keyword with the given argument";
return 1;
} }
std::string rq = "/keyword"; std::string rq = "/keyword";
@@ -172,28 +199,48 @@ void keywordRequest(int argc, char** argv) {
rq += " " + std::string(argv[i]); rq += " " + std::string(argv[i]);
request(rq); request(rq);
return 0;
} }
void hyprpaperRequest(int argc, char** argv) { int hyprpaperRequest(int argc, char** argv) {
if (argc < 4) { if (argc < 4) {
std::cout << "hyprpaper requires 2 params"; std::cout << "Usage: hyprctl hyprpaper <command> <arg>\n\
return; Execute a hyprpaper command with the given argument";
return 1;
} }
std::string rq = std::string(argv[2]) + " " + std::string(argv[3]); std::string rq = std::string(argv[2]) + " " + std::string(argv[3]);
requestHyprpaper(rq); requestHyprpaper(rq);
return 0;
} }
void setcursorRequest(int argc, char** argv) { int setcursorRequest(int argc, char** argv) {
if (argc < 4) { if (argc < 4) {
std::cout << "setcursor requires 2 params"; std::cout << "Usage: hyprctl setcursor <theme> <size>\n\
return; Sets the cursor theme for everything except GTK and reloads the cursor";
return 1;
} }
std::string rq = "setcursor " + std::string(argv[2]) + " " + std::string(argv[3]); std::string rq = "setcursor " + std::string(argv[2]) + " " + std::string(argv[3]);
request(rq); request(rq);
return 0;
}
int outputRequest(int argc, char** argv) {
if (argc < 4) {
std::cout << "Usage: hyprctl output <mode> <name>\n\
creates / destroys a fake output\n\
with create, name is the backend name to use (available: auto, x11, wayland, headless)\n\
with destroy, name is the output name to destroy";
return 1;
}
std::string rq = "output " + std::string(argv[2]) + " " + std::string(argv[3]);
request(rq);
return 0;
} }
void batchRequest(std::string arg) { void batchRequest(std::string arg) {
@@ -212,11 +259,14 @@ std::deque<std::string> splitArgs(int argc, char** argv) {
} }
bool isNumber(const std::string& str, bool allowfloat) { bool isNumber(const std::string& str, bool allowfloat) {
if (str.empty())
return false;
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); }); 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 main(int argc, char** argv) {
int bflag = 0, sflag = 0, index, c; int bflag = 0, sflag = 0, index, c;
bool parseArgs = true;
if (argc < 2) { if (argc < 2) {
printf("%s\n", USAGE.c_str()); printf("%s\n", USAGE.c_str());
@@ -228,7 +278,12 @@ int main(int argc, char** argv) {
const auto ARGS = splitArgs(argc, argv); const auto ARGS = splitArgs(argc, argv);
for (auto i = 0; i < ARGS.size(); ++i) { for (auto i = 0; i < ARGS.size(); ++i) {
if (ARGS[i][0] == '-' && !isNumber(ARGS[i], true) /* For stuff like -2 */) { if (ARGS[i] == "--") {
// Stop parsing arguments after --
parseArgs = false;
continue;
}
if (parseArgs && (ARGS[i][0] == '-') && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
// parse // parse
if (ARGS[i] == "-j" && !fullArgs.contains("j")) { if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
fullArgs += "j"; fullArgs += "j";
@@ -254,6 +309,8 @@ int main(int argc, char** argv) {
fullRequest = fullArgs + "/" + fullRequest; fullRequest = fullArgs + "/" + fullRequest;
int exitStatus = 0;
if (fullRequest.contains("/--batch")) batchRequest(fullRequest); if (fullRequest.contains("/--batch")) batchRequest(fullRequest);
else if (fullRequest.contains("/monitors")) request(fullRequest); else if (fullRequest.contains("/monitors")) request(fullRequest);
else if (fullRequest.contains("/clients")) request(fullRequest); else if (fullRequest.contains("/clients")) request(fullRequest);
@@ -266,10 +323,13 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/devices")) request(fullRequest); else if (fullRequest.contains("/devices")) request(fullRequest);
else if (fullRequest.contains("/reload")) request(fullRequest); else if (fullRequest.contains("/reload")) request(fullRequest);
else if (fullRequest.contains("/getoption")) request(fullRequest); else if (fullRequest.contains("/getoption")) request(fullRequest);
else if (fullRequest.contains("/setcursor")) setcursorRequest(argc, argv); else if (fullRequest.contains("/cursorpos")) request(fullRequest);
else if (fullRequest.contains("/dispatch")) dispatchRequest(argc, argv); else if (fullRequest.contains("/switchxkblayout")) request(fullRequest, 2);
else if (fullRequest.contains("/keyword")) keywordRequest(argc, argv); else if (fullRequest.contains("/output")) exitStatus = outputRequest(argc, argv);
else if (fullRequest.contains("/hyprpaper")) hyprpaperRequest(argc, argv); else if (fullRequest.contains("/setcursor")) exitStatus = setcursorRequest(argc, argv);
else if (fullRequest.contains("/dispatch")) exitStatus = dispatchRequest(argc, argv);
else if (fullRequest.contains("/keyword")) exitStatus = keywordRequest(argc, argv);
else if (fullRequest.contains("/hyprpaper")) exitStatus = hyprpaperRequest(argc, argv);
else if (fullRequest.contains("/--help")) printf("%s", USAGE.c_str()); else if (fullRequest.contains("/--help")) printf("%s", USAGE.c_str());
else { else {
printf("%s\n", USAGE.c_str()); printf("%s\n", USAGE.c_str());
@@ -277,5 +337,5 @@ int main(int argc, char** argv) {
} }
printf("\n"); printf("\n");
return 0; return exitStatus;
} }

View File

@@ -1,5 +1,5 @@
project('Hyprland', 'cpp', 'c', project('Hyprland', 'cpp', 'c',
version : '0.14.0beta', version : '0.18.0beta',
default_options : [ default_options : [
'warning_level=2', 'warning_level=2',
'default_library=static', 'default_library=static',
@@ -20,8 +20,8 @@ endif
GIT_BRANCH = run_command('git', 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip() GIT_BRANCH = run_command('git', 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip()
GIT_COMMIT_HASH = run_command('git', 'rev-parse', 'HEAD', check: false).stdout().strip() GIT_COMMIT_HASH = run_command('git', 'rev-parse', 'HEAD', check: false).stdout().strip()
GIT_COMMIT_MESSAGE = run_command('bash', '-c', 'git show | head -n 5 | tail -n 1', check: false).stdout().strip() GIT_COMMIT_MESSAGE = run_command('sh', '-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() GIT_DIRTY = run_command('sh', '-c', 'git diff-index --quiet HEAD -- || echo "dirty"', check: false).stdout().strip()
add_project_arguments( add_project_arguments(
[ [

View File

@@ -7,6 +7,7 @@
meson, meson,
ninja, ninja,
git, git,
hyprland-protocols,
libdrm, libdrm,
libinput, libinput,
libxcb, libxcb,
@@ -14,6 +15,7 @@
mesa, mesa,
mount, mount,
pango, pango,
pciutils,
wayland, wayland,
wayland-protocols, wayland-protocols,
wayland-scanner, wayland-scanner,
@@ -62,17 +64,16 @@ in
git git
libdrm libdrm
libinput libinput
libxcb
libxkbcommon libxkbcommon
mesa mesa
pango pango
wayland wayland
wayland-protocols wayland-protocols
wayland-scanner wayland-scanner
pciutils
(wlroots.override {inherit enableXWayland hidpiXWayland nvidiaPatches;}) (wlroots.override {inherit enableXWayland hidpiXWayland nvidiaPatches;})
xcbutilwm
] ]
++ lib.optional enableXWayland xwayland; ++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland];
mesonBuildType = mesonBuildType =
if debug if debug
@@ -92,6 +93,10 @@ in
# Fix hardcoded paths to /usr installation # Fix hardcoded paths to /usr installation
postPatch = '' postPatch = ''
sed -i "s#/usr#$out#" src/render/OpenGL.cpp sed -i "s#/usr#$out#" src/render/OpenGL.cpp
# for some reason rmdir doesn't work in a dirty tree
rmdir subprojects/hyprland-protocols || true
ln -s ${hyprland-protocols} subprojects/hyprland-protocols
''; '';
passthru.providedSessions = ["hyprland"]; passthru.providedSessions = ["hyprland"];

View File

@@ -92,18 +92,13 @@ in {
++ lib.optional cfg.xwayland.enable pkgs.xwayland; ++ lib.optional cfg.xwayland.enable pkgs.xwayland;
home.sessionVariables = lib.mkIf cfg.recommendedEnvironment { home.sessionVariables = lib.mkIf cfg.recommendedEnvironment {
GDK_BACKEND = "wayland";
_JAVA_AWT_WM_NONREPARENTING = "1";
NIXOS_OZONE_WL = "1"; NIXOS_OZONE_WL = "1";
XCURSOR_SIZE = toString config.home.pointerCursor.size or "24";
XDG_SESSION_TYPE = "wayland";
}; };
xdg.configFile."hypr/hyprland.conf" = { xdg.configFile."hypr/hyprland.conf" = {
text = text =
(lib.optionalString cfg.systemdIntegration '' (lib.optionalString cfg.systemdIntegration ''
exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && systemctl --user start hyprland-session.target
exec-once=systemctl --user start hyprland-session.target
'') '')
+ cfg.extraConfig; + cfg.extraConfig;

View File

@@ -1,5 +1,5 @@
# Copied from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/programs/sway.nix # Copied from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/programs/sway.nix
self: { inputs: {
config, config,
lib, lib,
pkgs, pkgs,
@@ -7,6 +7,11 @@ self: {
}: }:
with lib; let with lib; let
cfg = config.programs.hyprland; cfg = config.programs.hyprland;
defaultHyprlandPackage = inputs.self.packages.${pkgs.system}.default.override {
enableXWayland = cfg.xwayland.enable;
hidpiXWayland = cfg.xwayland.hidpi;
};
in { in {
imports = [ imports = [
(mkRemovedOptionModule ["programs" "hyprland" "extraPackages"] "extraPackages has been removed. Use environment.systemPackages instead.") (mkRemovedOptionModule ["programs" "hyprland" "extraPackages"] "extraPackages has been removed. Use environment.systemPackages instead.")
@@ -23,7 +28,7 @@ in {
package = mkOption { package = mkOption {
type = types.nullOr types.package; type = types.nullOr types.package;
default = self.packages.${pkgs.system}.default; default = defaultHyprlandPackage;
defaultText = literalExpression "<Hyprland flake>.packages.<system>.default"; defaultText = literalExpression "<Hyprland flake>.packages.<system>.default";
example = literalExpression "<Hyprland flake>.packages.<system>.default.override { }"; example = literalExpression "<Hyprland flake>.packages.<system>.default.override { }";
description = '' description = ''
@@ -31,6 +36,23 @@ in {
''; '';
}; };
xwayland = {
enable = mkOption {
type = types.bool;
default = true;
description = ''
Enable XWayland.
'';
};
hidpi = mkOption {
type = types.bool;
default = true;
description = ''
Enable HiDPI XWayland.
'';
};
};
recommendedEnvironment = mkOption { recommendedEnvironment = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
@@ -44,14 +66,10 @@ in {
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment = { environment = {
systemPackages = lib.optional (cfg.package != null) cfg.package; systemPackages = lib.optional (cfg.package != null) defaultHyprlandPackage;
sessionVariables = mkIf cfg.recommendedEnvironment { sessionVariables = mkIf cfg.recommendedEnvironment {
GDK_BACKEND = "wayland";
_JAVA_AWT_WM_NONREPARENTING = "1";
NIXOS_OZONE_WL = "1"; NIXOS_OZONE_WL = "1";
XCURSOR_SIZE = "24";
XDG_SESSION_TYPE = "wayland";
}; };
}; };
fonts.enableDefaultFonts = mkDefault true; fonts.enableDefaultFonts = mkDefault true;
@@ -61,10 +79,17 @@ in {
xwayland.enable = mkDefault true; xwayland.enable = mkDefault true;
}; };
security.polkit.enable = true; security.polkit.enable = true;
services.xserver.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package; services.xserver.displayManager.sessionPackages = lib.optional (cfg.package != null) defaultHyprlandPackage;
xdg.portal = { xdg.portal = {
enable = mkDefault true; enable = mkDefault true;
extraPortals = [pkgs.xdg-desktop-portal-wlr]; # xdg-desktop-portal-hyprland
extraPortals = lib.mkIf (cfg.package != null) [
(inputs.xdph.packages.${pkgs.system}.xdg-desktop-portal-hyprland.override {
hyprland-share-picker = inputs.xdph.packages.${pkgs.system}.hyprland-share-picker.override {
hyprland = defaultHyprlandPackage;
};
})
];
}; };
}; };
} }

View File

@@ -6,6 +6,7 @@
xwayland, xwayland,
fetchpatch, fetchpatch,
lib, lib,
hwdata,
hidpiXWayland ? true, hidpiXWayland ? true,
enableXWayland ? true, enableXWayland ? true,
nvidiaPatches ? false, nvidiaPatches ? false,
@@ -51,6 +52,7 @@ assert (lib.assertMsg (hidpiXWayland -> enableXWayland) ''
'' ''
else "" else ""
); );
buildInputs = old.buildInputs ++ [hwdata];
})) }))
.override { .override {
xwayland = xwayland.overrideAttrs (old: { xwayland = xwayland.overrideAttrs (old: {

View File

@@ -3,7 +3,14 @@ wayland_protos = dependency('wayland-protocols',
fallback: 'wayland-protocols', fallback: 'wayland-protocols',
default_options: ['tests=false'], default_options: ['tests=false'],
) )
hyprland_protos = dependency('hyprland-protocols',
version: '>=0.1',
fallback: 'hyprland-protocols',
)
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
wayland_scanner_dep = dependency('wayland-scanner', native: true) wayland_scanner_dep = dependency('wayland-scanner', native: true)
wayland_scanner = find_program( wayland_scanner = find_program(
@@ -13,12 +20,15 @@ wayland_scanner = find_program(
protocols = [ protocols = [
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
[wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
['wlr-foreign-toplevel-management-unstable-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'],
['wlr-output-power-management-unstable-v1.xml'], ['wlr-output-power-management-unstable-v1.xml'],
['ext-workspace-unstable-v1.xml'], ['ext-workspace-unstable-v1.xml'],
['pointer-constraints-unstable-v1.xml'], ['pointer-constraints-unstable-v1.xml'],
['tablet-unstable-v2.xml'], ['tablet-unstable-v2.xml'],
['idle.xml'] ['idle.xml'],
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml']
] ]
wl_protos_src = [] wl_protos_src = []
wl_protos_headers = [] wl_protos_headers = []

View File

@@ -0,0 +1,270 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_foreign_toplevel_management_unstable_v1">
<copyright>
Copyright © 2018 Ilia Bozhinov
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="zwlr_foreign_toplevel_manager_v1" version="3">
<description summary="list and control opened apps">
The purpose of this protocol is to enable the creation of taskbars
and docks by providing them with a list of opened applications and
letting them request certain actions on them, like maximizing, etc.
After a client binds the zwlr_foreign_toplevel_manager_v1, each opened
toplevel window will be sent via the toplevel event
</description>
<event name="toplevel">
<description summary="a toplevel has been created">
This event is emitted whenever a new toplevel window is created. It
is emitted for all toplevels, regardless of the app that has created
them.
All initial details of the toplevel(title, app_id, states, etc.) will
be sent immediately after this event via the corresponding events in
zwlr_foreign_toplevel_handle_v1.
</description>
<arg name="toplevel" type="new_id" interface="zwlr_foreign_toplevel_handle_v1"/>
</event>
<request name="stop">
<description summary="stop sending events">
Indicates the client no longer wishes to receive events for new toplevels.
However the compositor may emit further toplevel_created events, until
the finished event is emitted.
The client must not send any more requests after this one.
</description>
</request>
<event name="finished" type="destructor">
<description summary="the compositor has finished with the toplevel manager">
This event indicates that the compositor is done sending events to the
zwlr_foreign_toplevel_manager_v1. The server will destroy the object
immediately after sending this request, so it will become invalid and
the client should free any resources associated with it.
</description>
</event>
</interface>
<interface name="zwlr_foreign_toplevel_handle_v1" version="3">
<description summary="an opened toplevel">
A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
window. Each app may have multiple opened toplevels.
Each toplevel has a list of outputs it is visible on, conveyed to the
client with the output_enter and output_leave events.
</description>
<event name="title">
<description summary="title change">
This event is emitted whenever the title of the toplevel changes.
</description>
<arg name="title" type="string"/>
</event>
<event name="app_id">
<description summary="app-id change">
This event is emitted whenever the app-id of the toplevel changes.
</description>
<arg name="app_id" type="string"/>
</event>
<event name="output_enter">
<description summary="toplevel entered an output">
This event is emitted whenever the toplevel becomes visible on
the given output. A toplevel may be visible on multiple outputs.
</description>
<arg name="output" type="object" interface="wl_output"/>
</event>
<event name="output_leave">
<description summary="toplevel left an output">
This event is emitted whenever the toplevel stops being visible on
the given output. It is guaranteed that an entered-output event
with the same output has been emitted before this event.
</description>
<arg name="output" type="object" interface="wl_output"/>
</event>
<request name="set_maximized">
<description summary="requests that the toplevel be maximized">
Requests that the toplevel be maximized. If the maximized state actually
changes, this will be indicated by the state event.
</description>
</request>
<request name="unset_maximized">
<description summary="requests that the toplevel be unmaximized">
Requests that the toplevel be unmaximized. If the maximized state actually
changes, this will be indicated by the state event.
</description>
</request>
<request name="set_minimized">
<description summary="requests that the toplevel be minimized">
Requests that the toplevel be minimized. If the minimized state actually
changes, this will be indicated by the state event.
</description>
</request>
<request name="unset_minimized">
<description summary="requests that the toplevel be unminimized">
Requests that the toplevel be unminimized. If the minimized state actually
changes, this will be indicated by the state event.
</description>
</request>
<request name="activate">
<description summary="activate the toplevel">
Request that this toplevel be activated on the given seat.
There is no guarantee the toplevel will be actually activated.
</description>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
<enum name="state">
<description summary="types of states on the toplevel">
The different states that a toplevel can have. These have the same meaning
as the states with the same names defined in xdg-toplevel
</description>
<entry name="maximized" value="0" summary="the toplevel is maximized"/>
<entry name="minimized" value="1" summary="the toplevel is minimized"/>
<entry name="activated" value="2" summary="the toplevel is active"/>
<entry name="fullscreen" value="3" summary="the toplevel is fullscreen" since="2"/>
</enum>
<event name="state">
<description summary="the toplevel state changed">
This event is emitted immediately after the zlw_foreign_toplevel_handle_v1
is created and each time the toplevel state changes, either because of a
compositor action or because of a request in this protocol.
</description>
<arg name="state" type="array"/>
</event>
<event name="done">
<description summary="all information about the toplevel has been sent">
This event is sent after all changes in the toplevel state have been
sent.
This allows changes to the zwlr_foreign_toplevel_handle_v1 properties
to be seen as atomic, even if they happen via multiple events.
</description>
</event>
<request name="close">
<description summary="request that the toplevel be closed">
Send a request to the toplevel to close itself. The compositor would
typically use a shell-specific method to carry out this request, for
example by sending the xdg_toplevel.close event. However, this gives
no guarantees the toplevel will actually be destroyed. If and when
this happens, the zwlr_foreign_toplevel_handle_v1.closed event will
be emitted.
</description>
</request>
<request name="set_rectangle">
<description summary="the rectangle which represents the toplevel">
The rectangle of the surface specified in this request corresponds to
the place where the app using this protocol represents the given toplevel.
It can be used by the compositor as a hint for some operations, e.g
minimizing. The client is however not required to set this, in which
case the compositor is free to decide some default value.
If the client specifies more than one rectangle, only the last one is
considered.
The dimensions are given in surface-local coordinates.
Setting width=height=0 removes the already-set rectangle.
</description>
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="x" type="int"/>
<arg name="y" type="int"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</request>
<enum name="error">
<entry name="invalid_rectangle" value="0"
summary="the provided rectangle is invalid"/>
</enum>
<event name="closed">
<description summary="this toplevel has been destroyed">
This event means the toplevel has been destroyed. It is guaranteed there
won't be any more events for this zwlr_foreign_toplevel_handle_v1. The
toplevel itself becomes inert so any requests will be ignored except the
destroy request.
</description>
</event>
<request name="destroy" type="destructor">
<description summary="destroy the zwlr_foreign_toplevel_handle_v1 object">
Destroys the zwlr_foreign_toplevel_handle_v1 object.
This request should be called either when the client does not want to
use the toplevel anymore or after the closed event to finalize the
destruction of the object.
</description>
</request>
<!-- Version 2 additions -->
<request name="set_fullscreen" since="2">
<description summary="request that the toplevel be fullscreened">
Requests that the toplevel be fullscreened on the given output. If the
fullscreen state and/or the outputs the toplevel is visible on actually
change, this will be indicated by the state and output_enter/leave
events.
The output parameter is only a hint to the compositor. Also, if output
is NULL, the compositor should decide which output the toplevel will be
fullscreened on, if at all.
</description>
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
<request name="unset_fullscreen" since="2">
<description summary="request that the toplevel be unfullscreened">
Requests that the toplevel be unfullscreened. If the fullscreen state
actually changes, this will be indicated by the state event.
</description>
</request>
<!-- Version 3 additions -->
<event name="parent" since="3">
<description summary="parent change">
This event is emitted whenever the parent of the toplevel changes.
No event is emitted when the parent handle is destroyed by the client.
</description>
<arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/>
</event>
</interface>
</protocol>

View File

@@ -53,7 +53,7 @@ CCompositor::CCompositor() {
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr); wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
//wl_event_loop_add_signal(m_sWLEventLoop, SIGINT, handleCritSignal, nullptr); //wl_event_loop_add_signal(m_sWLEventLoop, SIGINT, handleCritSignal, nullptr);
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay); m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay, &m_sWLRSession);
if (!m_sWLRBackend) { if (!m_sWLRBackend) {
Debug::log(CRIT, "m_sWLRBackend was NULL!"); Debug::log(CRIT, "m_sWLRBackend was NULL!");
@@ -73,7 +73,14 @@ CCompositor::CCompositor() {
throw std::runtime_error("wlr_gles2_renderer_create_with_drm_fd() failed!"); throw std::runtime_error("wlr_gles2_renderer_create_with_drm_fd() failed!");
} }
wlr_renderer_init_wl_display(m_sWLRRenderer, m_sWLDisplay); wlr_renderer_init_wl_shm(m_sWLRRenderer, m_sWLDisplay);
if (wlr_renderer_get_dmabuf_texture_formats(m_sWLRRenderer)) {
if (wlr_renderer_get_drm_fd(m_sWLRRenderer) >= 0)
wlr_drm_create(m_sWLDisplay, m_sWLRRenderer);
m_sWLRLinuxDMABuf = wlr_linux_dmabuf_v1_create_with_renderer(m_sWLDisplay, 4, m_sWLRRenderer);
}
m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer); m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer);
@@ -107,7 +114,7 @@ CCompositor::CCompositor() {
m_sWLRScene = wlr_scene_create(); m_sWLRScene = wlr_scene_create();
wlr_scene_attach_output_layout(m_sWLRScene, m_sWLROutputLayout); wlr_scene_attach_output_layout(m_sWLRScene, m_sWLROutputLayout);
m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 4); m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 5);
m_sWLRCursor = wlr_cursor_create(); m_sWLRCursor = wlr_cursor_create();
wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout); wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout);
@@ -115,13 +122,16 @@ CCompositor::CCompositor() {
m_sWLRXCursorMgr = wlr_xcursor_manager_create(nullptr, 24); m_sWLRXCursorMgr = wlr_xcursor_manager_create(nullptr, 24);
wlr_xcursor_manager_load(m_sWLRXCursorMgr, 1); wlr_xcursor_manager_load(m_sWLRXCursorMgr, 1);
if (const auto XCURSORENV = getenv("XCURSOR_SIZE"); !XCURSORENV || std::string(XCURSORENV).empty())
setenv("XCURSOR_SIZE", "24", true);
m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0"); m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0");
m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend); m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend);
m_sWLRIdle = wlr_idle_create(m_sWLDisplay); m_sWLRIdle = wlr_idle_create(m_sWLDisplay);
m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay); m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay, 4);
m_sWLRServerDecoMgr = wlr_server_decoration_manager_create(m_sWLDisplay); m_sWLRServerDecoMgr = wlr_server_decoration_manager_create(m_sWLDisplay);
m_sWLRXDGDecoMgr = wlr_xdg_decoration_manager_v1_create(m_sWLDisplay); m_sWLRXDGDecoMgr = wlr_xdg_decoration_manager_v1_create(m_sWLDisplay);
@@ -162,11 +172,20 @@ CCompositor::CCompositor() {
m_sWLRPointerGestures = wlr_pointer_gestures_v1_create(m_sWLDisplay); m_sWLRPointerGestures = wlr_pointer_gestures_v1_create(m_sWLDisplay);
m_sWLRSession = wlr_backend_get_session(m_sWLRBackend);
m_sWLRTextInputMgr = wlr_text_input_manager_v3_create(m_sWLDisplay); m_sWLRTextInputMgr = wlr_text_input_manager_v3_create(m_sWLDisplay);
m_sWLRIMEMgr = wlr_input_method_manager_v2_create(m_sWLDisplay); m_sWLRIMEMgr = wlr_input_method_manager_v2_create(m_sWLDisplay);
m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay);
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLDisplay);
if (!m_sWLRHeadlessBackend) {
Debug::log(CRIT, "Couldn't create the headless backend");
throw std::runtime_error("wlr_headless_backend_create() failed!");
}
wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
} }
CCompositor::~CCompositor() { CCompositor::~CCompositor() {
@@ -223,6 +242,7 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLROutputPowerMgr->events.set_mode, &Events::listen_powerMgrSetMode, m_sWLROutputPowerMgr, "PowerMgr"); addWLSignal(&m_sWLROutputPowerMgr->events.set_mode, &Events::listen_powerMgrSetMode, m_sWLROutputPowerMgr, "PowerMgr");
addWLSignal(&m_sWLRIMEMgr->events.input_method, &Events::listen_newIME, m_sWLRIMEMgr, "IMEMgr"); addWLSignal(&m_sWLRIMEMgr->events.input_method, &Events::listen_newIME, m_sWLRIMEMgr, "IMEMgr");
addWLSignal(&m_sWLRTextInputMgr->events.text_input, &Events::listen_newTextInput, m_sWLRTextInputMgr, "TextInputMgr"); addWLSignal(&m_sWLRTextInputMgr->events.text_input, &Events::listen_newTextInput, m_sWLRTextInputMgr, "TextInputMgr");
addWLSignal(&m_sWLRActivation->events.request_activate, &Events::listen_activateXDG, m_sWLRActivation, "ActivationV1");
if(m_sWRLDRMLeaseMgr) if(m_sWRLDRMLeaseMgr)
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM"); addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
@@ -235,15 +255,15 @@ void CCompositor::cleanup() {
if (!m_sWLDisplay || m_bIsShuttingDown) if (!m_sWLDisplay || m_bIsShuttingDown)
return; return;
m_bIsShuttingDown = true;
m_pLastFocus = nullptr; m_pLastFocus = nullptr;
m_pLastWindow = nullptr; m_pLastWindow = nullptr;
// accumulate all PIDs for killing, also request closing. // accumulate all PIDs for killing, also request closing.
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_bIsMapped || !w->m_bIsX11) if (w->m_bIsMapped && !w->isHidden())
m_dProcessPIDsOnShutdown.push_back(w->getPID()); m_dProcessPIDsOnShutdown.push_back(w->getPID());
closeWindow(w.get());
} }
// end threads // end threads
@@ -259,6 +279,8 @@ void CCompositor::cleanup() {
wlr_output_commit(m->output); wlr_output_commit(m->output);
} }
m_vMonitors.clear();
if (g_pXWaylandManager->m_sWLRXWayland) { if (g_pXWaylandManager->m_sWLRXWayland) {
wlr_xwayland_destroy(g_pXWaylandManager->m_sWLRXWayland); wlr_xwayland_destroy(g_pXWaylandManager->m_sWLRXWayland);
g_pXWaylandManager->m_sWLRXWayland = nullptr; g_pXWaylandManager->m_sWLRXWayland = nullptr;
@@ -266,8 +288,6 @@ void CCompositor::cleanup() {
wl_display_terminate(m_sWLDisplay); wl_display_terminate(m_sWLDisplay);
m_bIsShuttingDown = true;
g_pKeybindManager->spawn("sleep 5 && kill -9 " + std::to_string(m_iHyprlandPID)); // this is to prevent that random "freezing" g_pKeybindManager->spawn("sleep 5 && kill -9 " + std::to_string(m_iHyprlandPID)); // this is to prevent that random "freezing"
// the PID should not be reused. // the PID should not be reused.
} }
@@ -306,6 +326,9 @@ void CCompositor::startCompositor() {
Debug::log(LOG, "Creating the XWaylandManager!"); Debug::log(LOG, "Creating the XWaylandManager!");
g_pXWaylandManager = std::make_unique<CHyprXWaylandManager>(); g_pXWaylandManager = std::make_unique<CHyprXWaylandManager>();
Debug::log(LOG, "Creating the ProtocolManager!");
g_pProtocolManager = std::make_unique<CProtocolManager>();
Debug::log(LOG, "Creating the EventManager!"); Debug::log(LOG, "Creating the EventManager!");
g_pEventManager = std::make_unique<CEventManager>(); g_pEventManager = std::make_unique<CEventManager>();
g_pEventManager->startThread(); g_pEventManager->startThread();
@@ -322,19 +345,28 @@ void CCompositor::startCompositor() {
initAllSignals(); initAllSignals();
m_szWLDisplaySocket = wl_display_add_socket_auto(m_sWLDisplay); // get socket, avoid using 0
for (int candidate = 1; candidate <= 32; candidate++) {
if (wl_display_add_socket(m_sWLDisplay, ("wayland-" + std::to_string(candidate)).c_str()) >= 0) {
m_szWLDisplaySocket = "wayland-" + std::to_string(candidate);
break;
}
}
if (!m_szWLDisplaySocket) { if (m_szWLDisplaySocket.empty()) {
Debug::log(CRIT, "m_szWLDisplaySocket NULL!"); Debug::log(CRIT, "m_szWLDisplaySocket NULL!");
wlr_backend_destroy(m_sWLRBackend); wlr_backend_destroy(m_sWLRBackend);
throw std::runtime_error("m_szWLDisplaySocket was null! (wl_display_add_socket_auto failed)"); throw std::runtime_error("m_szWLDisplaySocket was null! (wl_display_add_socket_auto failed)");
} }
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket, 1); setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
Debug::log(LOG, "Running on WAYLAND_DISPLAY: %s", m_szWLDisplaySocket); if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */ && fork() == 0)
execl("/bin/sh", "/bin/sh", "-c", "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE", nullptr);
Debug::log(LOG, "Running on WAYLAND_DISPLAY: %s", m_szWLDisplaySocket.c_str());
if (!wlr_backend_start(m_sWLRBackend)) { if (!wlr_backend_start(m_sWLRBackend)) {
Debug::log(CRIT, "Backend did not start!"); Debug::log(CRIT, "Backend did not start!");
@@ -406,7 +438,7 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) { void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) {
if (windowExists(pWindow) && !pWindow->m_bFadingOut){ if (windowExists(pWindow) && !pWindow->m_bFadingOut){
if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) {
m_dUnmanagedX11Windows.erase(std::remove_if(m_dUnmanagedX11Windows.begin(), m_dUnmanagedX11Windows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; })); std::erase_if(m_dUnmanagedX11Windows, [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; });
} }
// if X11, also check its children // if X11, also check its children
@@ -417,16 +449,16 @@ void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) {
continue; continue;
if (w->m_pX11Parent == pWindow) if (w->m_pX11Parent == pWindow)
m_vWindows.erase(std::remove_if(m_vWindows.begin(), m_vWindows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); })); std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); });
} }
for (auto& w : m_dUnmanagedX11Windows) { for (auto& w : m_dUnmanagedX11Windows) {
if (w->m_pX11Parent == pWindow) if (w->m_pX11Parent == pWindow)
m_dUnmanagedX11Windows.erase(std::remove_if(m_dUnmanagedX11Windows.begin(), m_dUnmanagedX11Windows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); })); std::erase_if(m_dUnmanagedX11Windows, [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); });
} }
} }
m_vWindows.erase(std::remove_if(m_vWindows.begin(), m_vWindows.end(), [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; })); std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; });
} }
} }
@@ -442,16 +474,16 @@ bool CCompositor::windowExists(CWindow* pWindow) {
CWindow* CCompositor::vectorToWindow(const Vector2D& pos) { CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
const auto PMONITOR = getMonitorFromVector(pos); const auto PMONITOR = getMonitorFromVector(pos);
if (PMONITOR->specialWorkspaceOpen) { if (PMONITOR->specialWorkspaceID) {
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->m_bHidden) if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == PMONITOR->specialWorkspaceID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden())
return (*w).get(); return (*w).get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->m_bHidden) if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden())
return w.get(); return w.get();
} }
} }
@@ -459,20 +491,20 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
// pinned // pinned
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, pos.x, pos.y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && !(*w)->m_bHidden && (*w)->m_bPinned) if (wlr_box_contains_point(&box, pos.x, pos.y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && !(*w)->isHidden() && (*w)->m_bPinned)
return w->get(); return w->get();
} }
// first loop over floating cuz they're above, m_vWindows should be sorted bottom->top, for tiled it doesn't matter. // first loop over floating cuz they're above, m_vWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, pos.x, pos.y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && !(*w)->m_bPinned) if (wlr_box_contains_point(&box, pos.x, pos.y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->isHidden() && !(*w)->m_bPinned)
return w->get(); return w->get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->m_bHidden) if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->isHidden())
return w.get(); return w.get();
} }
@@ -482,17 +514,17 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) { CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
const auto PMONITOR = getMonitorFromVector(pos); const auto PMONITOR = getMonitorFromVector(pos);
if (PMONITOR->specialWorkspaceOpen) { if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bIsFloating && !w->m_bHidden) if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bIsFloating && !w->isHidden())
return w.get(); return w.get();
} }
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->m_bHidden) if (w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->isHidden())
return w.get(); return w.get();
} }
@@ -512,16 +544,16 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
const auto PMONITOR = getMonitorFromVector(pos); const auto PMONITOR = getMonitorFromVector(pos);
// special workspace // special workspace
if (PMONITOR->specialWorkspaceOpen) { if (PMONITOR->specialWorkspaceID) {
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->m_bHidden && !(*w)->m_bX11ShouldntFocus) if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == PMONITOR->specialWorkspaceID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !(*w)->isHidden() && !(*w)->m_bX11ShouldntFocus)
return (*w).get(); return (*w).get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bHidden && !w->m_bX11ShouldntFocus) if (!w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() && !w->m_bX11ShouldntFocus)
return w.get(); return w.get();
} }
} }
@@ -529,7 +561,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// pinned windows on top of floating regardless // pinned windows on top of floating regardless
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if ((*w)->m_bIsFloating && (*w)->m_bIsMapped && !(*w)->m_bHidden && !(*w)->m_bX11ShouldntFocus && (*w)->m_bPinned) { if ((*w)->m_bIsFloating && (*w)->m_bIsMapped && !(*w)->isHidden() && !(*w)->m_bX11ShouldntFocus && (*w)->m_bPinned) {
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y)) if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y))
return w->get(); return w->get();
@@ -548,7 +580,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if ((*w)->m_bIsFloating && (*w)->m_bIsMapped && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && !(*w)->m_bPinned) { if ((*w)->m_bIsFloating && (*w)->m_bIsMapped && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->isHidden() && !(*w)->m_bPinned) {
// OR windows should add focus to parent // OR windows should add focus to parent
if ((*w)->m_bX11ShouldntFocus && (*w)->m_iX11Type != 2) if ((*w)->m_bX11ShouldntFocus && (*w)->m_iX11Type != 2)
continue; continue;
@@ -578,7 +610,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// for windows, we need to check their extensions too, first. // for windows, we need to check their extensions too, first.
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bHidden && !w->m_bX11ShouldntFocus) { if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus) {
wlr_surface* resultSurf = nullptr; wlr_surface* resultSurf = nullptr;
Vector2D origin = w->m_vRealPosition.vec(); Vector2D origin = w->m_vRealPosition.vec();
SExtensionFindingData data = {origin, pos, &resultSurf}; SExtensionFindingData data = {origin, pos, &resultSurf};
@@ -590,7 +622,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bHidden && !w->m_bX11ShouldntFocus) if (!w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus)
return w.get(); return w.get();
} }
@@ -600,16 +632,16 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
CWindow* CCompositor::windowFromCursor() { CWindow* CCompositor::windowFromCursor() {
const auto PMONITOR = getMonitorFromCursor(); const auto PMONITOR = getMonitorFromCursor();
if (PMONITOR->specialWorkspaceOpen) { if (PMONITOR->specialWorkspaceID) {
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && !(*w)->m_bHidden) if ((*w)->m_bIsFloating && (*w)->m_iWorkspaceID == PMONITOR->specialWorkspaceID && (*w)->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && !(*w)->isHidden())
return (*w).get(); return (*w).get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped) if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped)
return w.get(); return w.get();
} }
} }
@@ -640,13 +672,13 @@ CWindow* CCompositor::windowFromCursor() {
CWindow* CCompositor::windowFloatingFromCursor() { CWindow* CCompositor::windowFloatingFromCursor() {
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && !(*w)->m_bHidden && (*w)->m_bPinned) if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && !(*w)->isHidden() && (*w)->m_bPinned)
return w->get(); return w->get();
} }
for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) { for (auto w = m_vWindows.rbegin(); w != m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden && !(*w)->m_bPinned) if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && (*w)->m_bIsMapped && (*w)->m_bIsFloating && isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->isHidden() && !(*w)->m_bPinned)
return w->get(); return w->get();
} }
@@ -709,6 +741,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
if (windowValidMapped(PLASTWINDOW)) { if (windowValidMapped(PLASTWINDOW)) {
updateWindowAnimatedDecorationValues(PLASTWINDOW); updateWindowAnimatedDecorationValues(PLASTWINDOW);
g_pXWaylandManager->activateWindow(PLASTWINDOW, false);
if (PLASTWINDOW->m_phForeignToplevel) if (PLASTWINDOW->m_phForeignToplevel)
wlr_foreign_toplevel_handle_v1_set_activated(PLASTWINDOW->m_phForeignToplevel, false); wlr_foreign_toplevel_handle_v1_set_activated(PLASTWINDOW->m_phForeignToplevel, false);
} }
@@ -717,7 +751,11 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(nullptr);
m_pLastFocus = nullptr; m_pLastFocus = nullptr;
g_pInputManager->recheckIdleInhibitorStatus();
return; return;
} }
@@ -742,10 +780,8 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
if (windowValidMapped(PLASTWINDOW)) { if (windowValidMapped(PLASTWINDOW)) {
updateWindowAnimatedDecorationValues(PLASTWINDOW); updateWindowAnimatedDecorationValues(PLASTWINDOW);
if (PLASTWINDOW->m_bIsX11) { if (!pWindow->m_bIsX11 || pWindow->m_iX11Type == 1)
wlr_seat_keyboard_notify_clear_focus(m_sSeat.seat); g_pXWaylandManager->activateWindow(PLASTWINDOW, false);
wlr_seat_pointer_clear_focus(m_sSeat.seat);
}
if (PLASTWINDOW->m_phForeignToplevel) if (PLASTWINDOW->m_phForeignToplevel)
wlr_foreign_toplevel_handle_v1_set_activated(PLASTWINDOW->m_phForeignToplevel, false); wlr_foreign_toplevel_handle_v1_set_activated(PLASTWINDOW->m_phForeignToplevel, false);
@@ -768,8 +804,19 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
// Send an event // 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});
g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(pWindow);
if (pWindow->m_phForeignToplevel) if (pWindow->m_phForeignToplevel)
wlr_foreign_toplevel_handle_v1_set_activated(pWindow->m_phForeignToplevel, true); wlr_foreign_toplevel_handle_v1_set_activated(pWindow->m_phForeignToplevel, true);
if (!pWindow->m_bIsX11) {
const auto PCONSTRAINT = wlr_pointer_constraints_v1_constraint_for_surface(m_sWLRPointerConstraints, pWindow->m_uSurface.xdg->surface, m_sSeat.seat);
if (PCONSTRAINT)
g_pInputManager->constrainMouse(m_sSeat.mouse, PCONSTRAINT);
}
g_pInputManager->recheckIdleInhibitorStatus();
} }
void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) { void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
@@ -778,7 +825,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
return; // Don't focus when already focused on this. return; // Don't focus when already focused on this.
// Unfocus last surface if should // Unfocus last surface if should
if (m_pLastFocus && ((m_sSeat.seat->keyboard_state.focused_surface && wlr_surface_is_xdg_surface(m_pLastFocus)) || !pSurface)) if (m_pLastFocus && !pWindowOwner)
g_pXWaylandManager->activateSurface(m_pLastFocus, false); g_pXWaylandManager->activateSurface(m_pLastFocus, false);
if (!pSurface) { if (!pSurface) {
@@ -810,11 +857,14 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
else else
Debug::log(LOG, "Set keyboard focus to surface %x", pSurface); Debug::log(LOG, "Set keyboard focus to surface %x", pSurface);
g_pXWaylandManager->activateSurface(pSurface, false); g_pXWaylandManager->activateSurface(pSurface, true);
m_pLastFocus = pSurface; m_pLastFocus = pSurface;
} }
bool CCompositor::windowValidMapped(CWindow* pWindow) { bool CCompositor::windowValidMapped(CWindow* pWindow) {
if (!pWindow)
return false;
if (!windowExists(pWindow)) if (!windowExists(pWindow))
return false; return false;
@@ -824,7 +874,7 @@ bool CCompositor::windowValidMapped(CWindow* pWindow) {
if (!pWindow->m_bIsMapped) if (!pWindow->m_bIsMapped)
return false; return false;
if (pWindow->m_bHidden) if (pWindow->isHidden())
return false; return false;
return true; return true;
@@ -844,7 +894,11 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
if ((*it)->fadingOut || !(*it)->layerSurface || ((*it)->layerSurface && !(*it)->layerSurface->mapped) || (*it)->alpha.fl() == 0.f) if ((*it)->fadingOut || !(*it)->layerSurface || ((*it)->layerSurface && !(*it)->layerSurface->mapped) || (*it)->alpha.fl() == 0.f)
continue; continue;
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); 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 && VECINRECT(pos, (*it)->geometry.x, (*it)->geometry.y, (*it)->geometry.x + (*it)->geometry.width, (*it)->geometry.y + (*it)->geometry.height)) {
SURFACEAT = (*it)->layerSurface->surface;
}
if (SURFACEAT) { if (SURFACEAT) {
*ppLayerSurfaceFound = it->get(); *ppLayerSurfaceFound = it->get();
@@ -857,6 +911,9 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) { CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_bFadingOut || !w->m_bMappedX11)
continue;
if (g_pXWaylandManager->getWindowSurface(w.get()) == pSurface) if (g_pXWaylandManager->getWindowSurface(w.get()) == pSurface)
return w.get(); return w.get();
} }
@@ -864,6 +921,33 @@ CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
return nullptr; return nullptr;
} }
CWindow* CCompositor::getWindowFromHandle(uint32_t handle) {
for (auto& w : m_vWindows) {
if ((uint32_t)(((uint64_t)w.get()) & 0xFFFFFFFF) == handle) {
return w.get();
}
}
return nullptr;
}
CWindow* CCompositor::getWindowFromZWLRHandle(wl_resource* handle) {
for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->isHidden() || !w->m_phForeignToplevel)
continue;
wl_resource* current;
wl_list_for_each(current, &w->m_phForeignToplevel->resources, link) {
if (current == handle) {
return w.get();
}
}
}
return nullptr;
}
CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == ID && w->m_bIsFullscreen) if (w->m_iWorkspaceID == ID && w->m_bIsFullscreen)
@@ -878,7 +962,7 @@ bool CCompositor::isWorkspaceVisible(const int& w) {
if (m->activeWorkspace == w) if (m->activeWorkspace == w)
return true; return true;
if (m->specialWorkspaceOpen && w == SPECIAL_WORKSPACE_ID) if (m->specialWorkspaceID && isWorkspaceSpecial(w))
return true; return true;
} }
@@ -907,10 +991,8 @@ void CCompositor::sanityCheckWorkspaces() {
continue; continue;
} }
if ((*it)->m_iID == SPECIAL_WORKSPACE_ID && WINDOWSONWORKSPACE == 0) { if ((*it)->m_bIsSpecialWorkspace && WINDOWSONWORKSPACE == 0) {
for (auto& m : m_vMonitors) { getMonitorFromID((*it)->m_iMonitorID)->specialWorkspaceID = 0;
m->specialWorkspaceOpen = false;
}
it = m_vWorkspaces.erase(it); it = m_vWorkspaces.erase(it);
@@ -934,7 +1016,7 @@ int CCompositor::getWindowsOnWorkspace(const int& id) {
CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) { CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == id && w->m_bIsMapped && !w->m_bHidden) if (w->m_iWorkspaceID == id && w->m_bIsMapped && !w->isHidden())
return w.get(); return w.get();
} }
@@ -980,7 +1062,7 @@ void CCompositor::moveWindowToTop(CWindow* pWindow) {
std::deque<CWindow*> toMove; std::deque<CWindow*> toMove;
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_bIsMapped && w->m_bMappedX11 && !w->m_bHidden && w->m_bIsX11 && w->X11TransientFor() == pWindow) { if (w->m_bIsMapped && w->m_bMappedX11 && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pWindow) {
toMove.emplace_back(w.get()); toMove.emplace_back(w.get());
} }
} }
@@ -1006,8 +1088,9 @@ void CCompositor::cleanupFadingOut(const int& monid) {
g_pHyprOpenGL->m_mWindowFramebuffers[w].release(); g_pHyprOpenGL->m_mWindowFramebuffers[w].release();
g_pHyprOpenGL->m_mWindowFramebuffers.erase(w); g_pHyprOpenGL->m_mWindowFramebuffers.erase(w);
w->m_bFadingOut = false;
removeWindowFromVectorSafe(w); removeWindowFromVectorSafe(w);
m_vWindowsFadingOut.erase(std::remove(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), w)); std::erase(m_vWindowsFadingOut, w);
Debug::log(LOG, "Cleanup: destroyed a window"); Debug::log(LOG, "Cleanup: destroyed a window");
@@ -1103,7 +1186,11 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
CWindow* longestIntersectWindow = nullptr; CWindow* longestIntersectWindow = nullptr;
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w.get() == pWindow || !w->m_bIsMapped || w->m_bHidden || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID)) if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID))
continue;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen)
continue; continue;
const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
@@ -1177,12 +1264,12 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
continue; continue;
} }
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->m_bHidden && (!focusableOnly || !w->m_bNoFocus)) if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
return w.get(); return w.get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->m_bHidden && (!focusableOnly || !w->m_bNoFocus)) if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
return w.get(); return w.get();
} }
@@ -1200,12 +1287,12 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableO
continue; continue;
} }
if ((*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->m_bHidden && (!focusableOnly || !(*it)->m_bNoFocus)) if ((*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->isHidden() && (!focusableOnly || !(*it)->m_bNoFocus))
return it->get(); return it->get();
} }
for (auto it = m_vWindows.rbegin(); it != m_vWindows.rend(); it++) { for (auto it = m_vWindows.rbegin(); it != m_vWindows.rend(); it++) {
if (it->get() != pWindow && (*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->m_bHidden && (!focusableOnly || !(*it)->m_bNoFocus)) if (it->get() != pWindow && (*it)->m_iWorkspaceID == pWindow->m_iWorkspaceID && (*it)->m_bIsMapped && !(*it)->isHidden() && (!focusableOnly || !(*it)->m_bNoFocus))
return it->get(); return it->get();
} }
@@ -1255,6 +1342,11 @@ bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) {
return false; return false;
} }
void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) {
auto pair = (std::pair<wlr_surface*, bool>*)data;
pair->second = pair->second || pSurface == pair->first;
}
CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) { CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) {
if (!pMouse->currentConstraint) if (!pMouse->currentConstraint)
return nullptr; return nullptr;
@@ -1262,11 +1354,18 @@ CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) {
const auto PSURFACE = pMouse->currentConstraint->surface; const auto PSURFACE = pMouse->currentConstraint->surface;
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (PSURFACE == g_pXWaylandManager->getWindowSurface(w.get())) { if (w->isHidden() || !w->m_bMappedX11 || !w->m_bIsMapped || !g_pXWaylandManager->getWindowSurface(w.get()))
if (!w->m_bIsX11 && w->m_bIsMapped && !w->m_bHidden) continue;
continue;
return w.get(); if (w->m_bIsX11) {
if (PSURFACE == g_pXWaylandManager->getWindowSurface(w.get()))
return w.get();
} else {
std::pair<wlr_surface*, bool> check = {PSURFACE, false};
wlr_surface_for_each_surface(w->m_uSurface.xdg->surface, checkFocusSurfaceIter, &check);
if (check.second)
return w.get();
} }
} }
@@ -1345,8 +1444,8 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() {
void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) { void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
// optimization // optimization
static int64_t* ACTIVECOL = &g_pConfigManager->getConfigValuePtr("general:col.active_border")->intValue; static auto *const ACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.active_border")->data.get();
static int64_t* INACTIVECOL = &g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->intValue; static auto *const INACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->data.get();
static auto *const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue; 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 PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
static auto *const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue; static auto *const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue;
@@ -1354,31 +1453,36 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
static auto *const PSHADOWCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive")->intValue; static auto *const PSHADOWCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive")->intValue;
static auto *const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue; static auto *const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
auto setBorderColor = [&] (CGradientValueData grad) -> void {
if (grad == pWindow->m_cRealBorderColor)
return;
pWindow->m_cRealBorderColorPrevious = pWindow->m_cRealBorderColor;
pWindow->m_cRealBorderColor = grad;
pWindow->m_fBorderAnimationProgress.setValueAndWarp(0.f);
pWindow->m_fBorderAnimationProgress = 1.f;
};
// border // border
const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow); const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow);
if (RENDERDATA.isBorderColor) if (RENDERDATA.isBorderColor)
pWindow->m_cRealBorderColor = RENDERDATA.borderColor; setBorderColor(RENDERDATA.borderColor * (1.f / 255.f));
else else
pWindow->m_cRealBorderColor = CColor(pWindow == m_pLastWindow ? *ACTIVECOL : *INACTIVECOL); setBorderColor(pWindow == m_pLastWindow ?
(pWindow->m_sSpecialRenderData.activeBorderColor >= 0 ? CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor) * (1.f / 255.f)) : *ACTIVECOL) :
(pWindow->m_sSpecialRenderData.inactiveBorderColor >= 0 ? CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor) * (1.f / 255.f)) : *INACTIVECOL));
// opacity // opacity
if (pWindow->m_bIsFullscreen) { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
pWindow->m_fActiveInactiveAlpha = *PFULLSCREENALPHA;
if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL)
pWindow->m_fActiveInactiveAlpha = *PFULLSCREENALPHA;
else {
if (pWindow == m_pLastWindow)
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alpha * *PACTIVEALPHA;
else
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? pWindow->m_sSpecialRenderData.alphaInactive * *PINACTIVEALPHA : *PINACTIVEALPHA;
}
} else { } else {
if (pWindow == m_pLastWindow) if (pWindow == m_pLastWindow)
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alpha * *PACTIVEALPHA; pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaOverride ? pWindow->m_sSpecialRenderData.alpha : pWindow->m_sSpecialRenderData.alpha * *PACTIVEALPHA;
else else
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? pWindow->m_sSpecialRenderData.alphaInactive * *PINACTIVEALPHA : *PINACTIVEALPHA; pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive != -1 ? (pWindow->m_sSpecialRenderData.alphaInactiveOverride ? pWindow->m_sSpecialRenderData.alphaInactive : pWindow->m_sSpecialRenderData.alphaInactive * *PINACTIVEALPHA) : *PINACTIVEALPHA;
} }
// dim // dim
@@ -1480,7 +1584,41 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
} }
CMonitor* CCompositor::getMonitorFromString(const std::string& name) { CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
if (isNumber(name)) { if (name[0] == '+' || name[0] == '-') {
// relative
const auto OFFSET = name[0] == '-' ? name : name.substr(1);
if (!isNumber(OFFSET)) {
Debug::log(ERR, "Error in getMonitorFromString: Not a number in relative.");
return nullptr;
}
int offsetLeft = std::stoi(OFFSET);
offsetLeft = offsetLeft < 0 ? -((-offsetLeft) % m_vMonitors.size()) : offsetLeft % m_vMonitors.size();
int currentPlace = 0;
for (int i = 0; i < (int)m_vMonitors.size(); i++) {
if (m_vMonitors[i].get() == m_pLastMonitor) {
currentPlace = i;
break;
}
}
currentPlace += offsetLeft;
if (currentPlace < 0) {
currentPlace = m_vMonitors.size() - currentPlace;
} else {
currentPlace = currentPlace % m_vMonitors.size();
}
if (currentPlace != std::clamp(currentPlace, 0, (int)m_vMonitors.size())) {
Debug::log(WARN, "Error in getMonitorFromString: Vaxry's code sucks.");
currentPlace = std::clamp(currentPlace, 0, (int)m_vMonitors.size());
}
return m_vMonitors[currentPlace].get();
} else if (isNumber(name)) {
// change by ID // change by ID
int monID = -1; int monID = -1;
try { try {
@@ -1543,7 +1681,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
if (nextWorkspaceOnMonitorID == -1) { if (nextWorkspaceOnMonitorID == -1) {
nextWorkspaceOnMonitorID = 1; nextWorkspaceOnMonitorID = 1;
while (getWorkspaceByID(nextWorkspaceOnMonitorID)) while (getWorkspaceByID(nextWorkspaceOnMonitorID) || [&]() -> bool { const auto B = g_pConfigManager->getBoundMonitorForWS(std::to_string(nextWorkspaceOnMonitorID)); return B && B != POLDMON; }())
nextWorkspaceOnMonitorID++; nextWorkspaceOnMonitorID++;
Debug::log(LOG, "moveWorkspaceToMonitor: Plugging gap with new %d", nextWorkspaceOnMonitorID); Debug::log(LOG, "moveWorkspaceToMonitor: Plugging gap with new %d", nextWorkspaceOnMonitorID);
@@ -1564,7 +1702,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
w->m_iMonitorID = pMonitor->ID; w->m_iMonitorID = pMonitor->ID;
// additionally, move floating and fs windows manually // additionally, move floating and fs windows manually
if (w->m_bIsMapped && !w->m_bHidden) { if (w->m_bIsMapped && !w->isHidden()) {
if (w->m_bIsFloating) if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.vec() - POLDMON->vecPosition + pMonitor->vecPosition; w->m_vRealPosition = w->m_vRealPosition.vec() - POLDMON->vecPosition + pMonitor->vecPosition;
@@ -1606,7 +1744,7 @@ bool CCompositor::workspaceIDOutOfBounds(const int& id) {
int highestID = -99999; int highestID = -99999;
for (auto& w : m_vWorkspaces) { for (auto& w : m_vWorkspaces) {
if (w->m_iID == SPECIAL_WORKSPACE_ID) if (w->m_bIsSpecialWorkspace)
continue; continue;
if (w->m_iID < lowestID) if (w->m_iID < lowestID)
@@ -1641,12 +1779,15 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL); g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL);
pWindow->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
// make all windows on the same workspace under the fullscreen window // make all windows on the same workspace under the fullscreen window
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID) { if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID) {
w->m_bCreatedOverFullscreen = false; w->m_bCreatedOverFullscreen = false;
if (w.get() != pWindow && !w->m_bFadingOut && !w->m_bPinned) if (w.get() != pWindow && !w->m_bFadingOut && !w->m_bPinned)
w->m_fAlpha = pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL ? 0.f : 255.f; w->m_fAlpha = pWindow->m_bIsFullscreen ? 0.f : 255.f;
} }
} }
@@ -1658,6 +1799,11 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv(), true); g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv(), true);
forceReportSizesToWindowsOnWorkspace(pWindow->m_iWorkspaceID); forceReportSizesToWindowsOnWorkspace(pWindow->m_iWorkspaceID);
g_pInputManager->recheckIdleInhibitorStatus();
// DMAbuf stuff for direct scanout
g_pHyprRenderer->setWindowScanoutMode(pWindow);
} }
void CCompositor::moveUnmanagedX11ToWindows(CWindow* pWindow) { void CCompositor::moveUnmanagedX11ToWindows(CWindow* pWindow) {
@@ -1698,6 +1844,9 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive) if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
return; return;
if (!pMonitor->m_bEnabled)
return;
wlr_output_schedule_frame(pMonitor->output); wlr_output_schedule_frame(pMonitor->output);
} }
@@ -1718,7 +1867,7 @@ CWindow* CCompositor::getWindowByRegex(const std::string& regexp) {
} }
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_bHidden) if (!w->m_bIsMapped || w->isHidden())
continue; continue;
switch (mode) { switch (mode) {
@@ -1770,7 +1919,7 @@ void CCompositor::warpCursorTo(const Vector2D& pos) {
const auto PMONITORNEW = getMonitorFromVector(pos); const auto PMONITORNEW = getMonitorFromVector(pos);
if (PMONITORNEW != m_pLastMonitor) if (PMONITORNEW != m_pLastMonitor)
m_pLastMonitor = PMONITORNEW; setActiveMonitor(PMONITORNEW);
} }
SLayerSurface* CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) { SLayerSurface* CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) {
@@ -1846,7 +1995,7 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) { void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == wid && w->m_bIsMapped && !w->m_bHidden) { if (w->m_iWorkspaceID == wid && w->m_bIsMapped && !w->isHidden()) {
g_pXWaylandManager->setWindowSize(w.get(), w->m_vRealSize.vec(), true); g_pXWaylandManager->setWindowSize(w.get(), w->m_vRealSize.vec(), true);
} }
} }
@@ -1862,3 +2011,56 @@ bool CCompositor::cursorOnReservedArea() {
return !VECINRECT(CURSORPOS, XY1.x, XY1.y, XY2.x, XY2.y); return !VECINRECT(CURSORPOS, XY1.x, XY1.y, XY2.x, XY2.y);
} }
CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name) {
const auto NAME = name == "" ? std::to_string(id) : name;
auto monID = monid;
// check if bound
if (const auto PMONITOR = g_pConfigManager->getBoundMonitorForWS(NAME); PMONITOR) {
monID = PMONITOR->ID;
}
const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2;
const auto PWORKSPACE = m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(monID, NAME, SPECIAL)).get();
// We are required to set the name here immediately
if (!SPECIAL)
wlr_ext_workspace_handle_v1_set_name(PWORKSPACE->m_pWlrHandle, NAME.c_str());
PWORKSPACE->m_iID = id;
PWORKSPACE->m_iMonitorID = monID;
return PWORKSPACE;
}
void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
if (m_pLastMonitor == pMonitor)
return;
if (!pMonitor) {
m_pLastMonitor = nullptr;
return;
}
const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace);
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + PWORKSPACE->m_szName});
m_pLastMonitor = pMonitor;
}
bool CCompositor::isWorkspaceSpecial(const int& id) {
return id >= SPECIAL_WORKSPACE_START && id <= -2;
}
int CCompositor::getNewSpecialID() {
int highest = -100;
for (auto& ws : m_vWorkspaces) {
if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) {
highest = ws->m_iID;
}
}
return highest + 1;
}

View File

@@ -15,6 +15,7 @@
#include "managers/KeybindManager.hpp" #include "managers/KeybindManager.hpp"
#include "managers/AnimationManager.hpp" #include "managers/AnimationManager.hpp"
#include "managers/EventManager.hpp" #include "managers/EventManager.hpp"
#include "managers/ProtocolManager.hpp"
#include "debug/HyprDebugOverlay.hpp" #include "debug/HyprDebugOverlay.hpp"
#include "helpers/Monitor.hpp" #include "helpers/Monitor.hpp"
#include "helpers/Workspace.hpp" #include "helpers/Workspace.hpp"
@@ -69,12 +70,15 @@ public:
wlr_output_power_manager_v1* m_sWLROutputPowerMgr; wlr_output_power_manager_v1* m_sWLROutputPowerMgr;
wlr_input_method_manager_v2* m_sWLRIMEMgr; wlr_input_method_manager_v2* m_sWLRIMEMgr;
wlr_text_input_manager_v3* m_sWLRTextInputMgr; wlr_text_input_manager_v3* m_sWLRTextInputMgr;
wlr_xdg_activation_v1* m_sWLRActivation;
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
wlr_backend* m_sWLRHeadlessBackend;
// ------------------------------------------------- // // ------------------------------------------------- //
const char* m_szWLDisplaySocket; std::string m_szWLDisplaySocket = "";
std::string m_szInstanceSignature = ""; std::string m_szInstanceSignature = "";
std::string m_szCurrentSplash = "error"; std::string m_szCurrentSplash = "error";
std::vector<std::shared_ptr<CMonitor>> 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::shared_ptr<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
@@ -89,17 +93,17 @@ public:
void startCompositor(); void startCompositor();
void cleanup(); void cleanup();
wlr_surface* m_pLastFocus = nullptr; wlr_surface* m_pLastFocus = nullptr;
CWindow* m_pLastWindow = nullptr; CWindow* m_pLastWindow = nullptr;
CMonitor* m_pLastMonitor = nullptr; CMonitor* m_pLastMonitor = nullptr;
SSeat m_sSeat; SSeat m_sSeat;
bool m_bReadyToProcess = false; bool m_bReadyToProcess = false;
bool m_bSessionActive = true; bool m_bSessionActive = true;
bool m_bDPMSStateON = true; bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bIsShuttingDown = false; bool m_bIsShuttingDown = false;
std::deque<uint64_t> m_dProcessPIDsOnShutdown; // stores PIDs of apps to kill later when shutting down std::deque<uint64_t> m_dProcessPIDsOnShutdown; // stores PIDs of apps to kill later when shutting down
// ------------------------------------------------- // // ------------------------------------------------- //
@@ -123,6 +127,8 @@ public:
CMonitor* getMonitorFromOutput(wlr_output*); CMonitor* getMonitorFromOutput(wlr_output*);
CWindow* getWindowForPopup(wlr_xdg_popup*); CWindow* getWindowForPopup(wlr_xdg_popup*);
CWindow* getWindowFromSurface(wlr_surface*); CWindow* getWindowFromSurface(wlr_surface*);
CWindow* getWindowFromHandle(uint32_t);
CWindow* getWindowFromZWLRHandle(wl_resource*);
bool isWorkspaceVisible(const int&); bool isWorkspaceVisible(const int&);
CWorkspace* getWorkspaceByID(const int&); CWorkspace* getWorkspaceByID(const int&);
CWorkspace* getWorkspaceByName(const std::string&); CWorkspace* getWorkspaceByName(const std::string&);
@@ -165,6 +171,10 @@ public:
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const int&); void forceReportSizesToWindowsOnWorkspace(const int&);
bool cursorOnReservedArea(); bool cursorOnReservedArea();
CWorkspace* createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused!
void setActiveMonitor(CMonitor*);
bool isWorkspaceSpecial(const int&);
int getNewSpecialID();
std::string explicitConfigPath; std::string explicitConfigPath;

View File

@@ -3,9 +3,9 @@
#include "render/decorations/CHyprDropShadowDecoration.hpp" #include "render/decorations/CHyprDropShadowDecoration.hpp"
CWindow::CWindow() { CWindow::CWindow() {
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (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_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_fBorderAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE); 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_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_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
@@ -59,6 +59,13 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
auto POS = m_vPosition; auto POS = m_vPosition;
auto SIZE = m_vSize; auto SIZE = m_vSize;
if (m_bIsFullscreen) {
POS = PMONITOR->vecPosition;
SIZE = PMONITOR->vecSize;
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
}
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) { if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
POS.y = PMONITOR->vecPosition.y; POS.y = PMONITOR->vecPosition.y;
SIZE.y += PMONITOR->vecReservedTopLeft.y; SIZE.y += PMONITOR->vecReservedTopLeft.y;
@@ -244,3 +251,142 @@ void CWindow::removeDecorationByType(eDecorationType type) {
updateWindowDecos(); updateWindowDecos();
} }
void unregisterVar(void* ptr) {
((CAnimatedVariable*)ptr)->unregister();
}
void CWindow::onUnmap() {
if (g_pCompositor->m_pLastWindow == this)
g_pCompositor->m_pLastWindow = nullptr;
m_vRealPosition.setCallbackOnEnd(unregisterVar);
m_vRealSize.setCallbackOnEnd(unregisterVar);
m_fBorderAnimationProgress.setCallbackOnEnd(unregisterVar);
m_fActiveInactiveAlpha.setCallbackOnEnd(unregisterVar);
m_fAlpha.setCallbackOnEnd(unregisterVar);
m_cRealShadowColor.setCallbackOnEnd(unregisterVar);
m_fDimPercent.setCallbackOnEnd(unregisterVar);
m_vRealSize.setCallbackOnBegin(nullptr);
}
void CWindow::onMap() {
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
m_vRealPosition.resetAllCallbacks();
m_vRealSize.resetAllCallbacks();
m_fBorderAnimationProgress.resetAllCallbacks();
m_fActiveInactiveAlpha.resetAllCallbacks();
m_fAlpha.resetAllCallbacks();
m_cRealShadowColor.resetAllCallbacks();
m_fDimPercent.resetAllCallbacks();
m_vRealPosition.registerVar();
m_vRealSize.registerVar();
m_fBorderAnimationProgress.registerVar();
m_fActiveInactiveAlpha.registerVar();
m_fAlpha.registerVar();
m_cRealShadowColor.registerVar();
m_fDimPercent.registerVar();
m_vRealSize.setCallbackOnEnd([&] (void* ptr) {
g_pHyprOpenGL->onWindowResizeEnd(this);
}, false);
m_vRealSize.setCallbackOnBegin([&] (void* ptr) {
g_pHyprOpenGL->onWindowResizeStart(this);
}, false);
}
void CWindow::setHidden(bool hidden) {
m_bHidden = hidden;
if (hidden && g_pCompositor->m_pLastWindow == this) {
g_pCompositor->m_pLastWindow = nullptr;
}
}
bool CWindow::isHidden() {
return m_bHidden;
}
void CWindow::applyDynamicRule(const SWindowRule& r) {
if (r.szRule == "noblur") {
m_sAdditionalConfigData.forceNoBlur = true;
} else if (r.szRule == "noborder") {
m_sAdditionalConfigData.forceNoBorder = true;
} else if (r.szRule == "noshadow") {
m_sAdditionalConfigData.forceNoShadow = true;
} else if (r.szRule == "opaque") {
if (!m_sAdditionalConfigData.forceOpaqueOverriden)
m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule.find("rounding") == 0) {
try {
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) {
Debug::log(ERR, "Rounding rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
}
} else if (r.szRule.find("opacity") == 0) {
try {
CVarList vars(r.szRule, 0, ' ');
for (size_t i = 1 /* first item is "opacity" */; i < vars.size(); ++i) {
if (i == 1) {
// first arg, alpha
m_sSpecialRenderData.alpha = std::stof(vars[i]);
} else {
if (vars[i] == "override") {
if (i == 2) {
m_sSpecialRenderData.alphaOverride = true;
} else {
m_sSpecialRenderData.alphaInactiveOverride = true;
}
} else {
m_sSpecialRenderData.alphaInactive = std::stof(vars[i]);
}
}
}
} catch(std::exception& e) {
Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
}
} else if (r.szRule == "noanim") {
m_sAdditionalConfigData.forceNoAnims = true;
} else if (r.szRule.find("animation") == 0) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sAdditionalConfigData.animationStyle = STYLE;
} else if (r.szRule.find("bordercolor") == 0) {
try {
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
if (colorPart.contains(' ')) {
// we have a space, 2 values
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart.substr(0, colorPart.find_first_of(' ')));
m_sSpecialRenderData.inactiveBorderColor = configStringToInt(colorPart.substr(colorPart.find_first_of(' ') + 1));
} else {
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
}
} catch(std::exception& e) {
Debug::log(ERR, "BorderColor rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
}
}
}
void CWindow::updateDynamicRules() {
m_sSpecialRenderData.activeBorderColor = -1;
m_sSpecialRenderData.inactiveBorderColor = -1;
m_sSpecialRenderData.alpha = 1.f;
m_sSpecialRenderData.alphaInactive = -1.f;
m_sAdditionalConfigData.forceNoBlur = false;
m_sAdditionalConfigData.forceNoBorder = false;
m_sAdditionalConfigData.forceNoShadow = false;
if (!m_sAdditionalConfigData.forceOpaqueOverriden)
m_sAdditionalConfigData.forceOpaque = false;
m_sAdditionalConfigData.forceNoAnims = false;
m_sAdditionalConfigData.animationStyle = "";
m_sAdditionalConfigData.rounding = -1;
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
for (auto& r : WINDOWRULES) {
applyDynamicRule(r);
}
}

View File

@@ -6,11 +6,24 @@
#include "helpers/AnimatedVariable.hpp" #include "helpers/AnimatedVariable.hpp"
#include "render/decorations/IHyprWindowDecoration.hpp" #include "render/decorations/IHyprWindowDecoration.hpp"
#include <deque> #include <deque>
#include "config/ConfigDataValues.hpp"
enum eIdleInhibitMode {
IDLEINHIBIT_NONE = 0,
IDLEINHIBIT_ALWAYS,
IDLEINHIBIT_FULLSCREEN,
IDLEINHIBIT_FOCUS
};
struct SWindowSpecialRenderData { struct SWindowSpecialRenderData {
bool alphaOverride = false;
float alpha = 1.f; float alpha = 1.f;
bool alphaInactiveOverride = false;
float alphaInactive = -1.f; // -1 means unset float alphaInactive = -1.f; // -1 means unset
int64_t activeBorderColor = -1; // -1 means unset
int64_t inactiveBorderColor = -1; // -1 means unset
// set by the layout // set by the layout
bool rounding = true; bool rounding = true;
bool border = true; bool border = true;
@@ -22,7 +35,26 @@ struct SWindowAdditionalConfigData {
int rounding = -1; // -1 means no int rounding = -1; // -1 means no
bool forceNoBlur = false; bool forceNoBlur = false;
bool forceOpaque = false; bool forceOpaque = false;
bool forceOpaqueOverriden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
bool forceAllowsInput = false; bool forceAllowsInput = false;
bool forceNoAnims = false;
bool forceNoBorder = false;
bool forceNoShadow = false;
bool windowDanceCompat = false;
bool noMaxSize = false;
};
struct SWindowRule {
std::string szRule;
std::string szValue;
bool v2 = false;
std::string szTitle;
std::string szClass;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
int bFullscreen = -1;
int bPinned = -1;
}; };
class CWindow { class CWindow {
@@ -102,13 +134,16 @@ public:
bool m_bNoFocus = false; bool m_bNoFocus = false;
bool m_bNoInitialFocus = false; bool m_bNoInitialFocus = false;
// initial fullscreen // initial fullscreen and fullscreen disabled
bool m_bWantsInitialFullscreen = false; bool m_bWantsInitialFullscreen = false;
bool m_bNoFullscreenRequest = false;
SSurfaceTreeNode* m_pSurfaceTree = nullptr; SSurfaceTreeNode* m_pSurfaceTree = nullptr;
// Animated border // Animated border
CAnimatedVariable m_cRealBorderColor; CGradientValueData m_cRealBorderColor = {0};
CGradientValueData m_cRealBorderColorPrevious = {0};
CAnimatedVariable m_fBorderAnimationProgress;
// Fade in-out // Fade in-out
CAnimatedVariable m_fAlpha; CAnimatedVariable m_fAlpha;
@@ -117,9 +152,6 @@ public:
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
Vector2D m_vOriginalClosedSize; // drawing the closing animations Vector2D m_vOriginalClosedSize; // drawing the closing animations
// For hidden windows and stuff
bool m_bHidden = false;
// For pinned (sticky) windows // For pinned (sticky) windows
bool m_bPinned = false; bool m_bPinned = false;
@@ -153,6 +185,9 @@ public:
uint64_t m_iLastToplevelMonitorID = -1; uint64_t m_iLastToplevelMonitorID = -1;
uint64_t m_iLastSurfaceMonitorID = -1; uint64_t m_iLastSurfaceMonitorID = -1;
// for idle inhibiting windows
eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE;
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) { bool operator==(const CWindow& rhs) {
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut; return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut;
@@ -171,4 +206,15 @@ public:
void updateSurfaceOutputs(); void updateSurfaceOutputs();
void moveToWorkspace(int); void moveToWorkspace(int);
CWindow* X11TransientFor(); CWindow* X11TransientFor();
void onUnmap();
void onMap();
void setHidden(bool hidden);
bool isHidden();
void applyDynamicRule(const SWindowRule& r);
void updateDynamicRules();
private:
// For hidden windows and stuff
bool m_bHidden = false;
}; };

View File

@@ -0,0 +1,48 @@
#pragma once
#include "../defines.hpp"
enum eConfigValueDataTypes {
CVD_TYPE_INVALID = -1,
CVD_TYPE_GRADIENT = 0
};
interface ICustomConfigValueData {
public:
virtual ~ICustomConfigValueData() = 0;
virtual eConfigValueDataTypes getDataType() = 0;
};
class CGradientValueData : public ICustomConfigValueData {
public:
CGradientValueData(CColor col) {
m_vColors.push_back(col);
};
virtual ~CGradientValueData() { };
virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_GRADIENT;
}
void reset(CColor col) {
m_vColors.clear();
m_vColors.emplace_back(col);
m_fAngle = 0;
}
/* Vector containing the colors */
std::vector<CColor> m_vColors;
/* Float corresponding to the angle (rad) */
float m_fAngle = 0;
bool operator==(const CGradientValueData& other) {
if (other.m_vColors.size() != m_vColors.size() || m_fAngle != other.m_fAngle)
return false;
for (size_t i = 0; i < m_vColors.size(); ++i)
if (m_vColors[i] != other.m_vColors[i]) return false;
return true;
}
};

View File

@@ -11,6 +11,9 @@
#include <iostream> #include <iostream>
CConfigManager::CConfigManager() { CConfigManager::CConfigManager() {
configValues["general:col.active_border"].data = std::make_shared<CGradientValueData>(0xffffffff);
configValues["general:col.inactive_border"].data = std::make_shared<CGradientValueData>(0xff444444);
setDefaultVars(); setDefaultVars();
setDefaultAnimationVars(); setDefaultAnimationVars();
@@ -35,15 +38,12 @@ void CConfigManager::setDefaultVars() {
configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated
configValues["general:damage_tracking"].strValue = "full";
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_FULL;
configValues["general:border_size"].intValue = 1; configValues["general:border_size"].intValue = 1;
configValues["general:no_border_on_floating"].intValue = 0; configValues["general:no_border_on_floating"].intValue = 0;
configValues["general:gaps_in"].intValue = 5; configValues["general:gaps_in"].intValue = 5;
configValues["general:gaps_out"].intValue = 20; configValues["general:gaps_out"].intValue = 20;
configValues["general:col.active_border"].intValue = 0xffffffff; ((CGradientValueData*)configValues["general:col.active_border"].data.get())->reset(0xffffffff);
configValues["general:col.inactive_border"].intValue = 0xff444444; ((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
configValues["general:cursor_inactive_timeout"].intValue = 0; configValues["general:cursor_inactive_timeout"].intValue = 0;
configValues["general:no_cursor_warps"].intValue = 0; configValues["general:no_cursor_warps"].intValue = 0;
@@ -60,6 +60,8 @@ void CConfigManager::setDefaultVars() {
configValues["misc:disable_autoreload"].intValue = 0; configValues["misc:disable_autoreload"].intValue = 0;
configValues["misc:enable_swallow"].intValue = 0; configValues["misc:enable_swallow"].intValue = 0;
configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY; configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
configValues["misc:focus_on_activate"].intValue = 0;
configValues["misc:no_direct_scanout"].intValue = 0;
configValues["debug:int"].intValue = 0; configValues["debug:int"].intValue = 0;
configValues["debug:log_damage"].intValue = 0; configValues["debug:log_damage"].intValue = 0;
@@ -67,13 +69,15 @@ void CConfigManager::setDefaultVars() {
configValues["debug:damage_blink"].intValue = 0; configValues["debug:damage_blink"].intValue = 0;
configValues["debug:disable_logs"].intValue = 0; configValues["debug:disable_logs"].intValue = 0;
configValues["debug:disable_time"].intValue = 1; configValues["debug:disable_time"].intValue = 1;
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
configValues["decoration:rounding"].intValue = 0; configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur"].intValue = 1; configValues["decoration:blur"].intValue = 1;
configValues["decoration:blur_size"].intValue = 8; configValues["decoration:blur_size"].intValue = 8;
configValues["decoration:blur_passes"].intValue = 1; configValues["decoration:blur_passes"].intValue = 1;
configValues["decoration:blur_ignore_opacity"].intValue = 0; configValues["decoration:blur_ignore_opacity"].intValue = 0;
configValues["decoration:blur_new_optimizations"].intValue = 0; configValues["decoration:blur_new_optimizations"].intValue = 1;
configValues["decoration:blur_xray"].intValue = 0;
configValues["decoration:active_opacity"].floatValue = 1; configValues["decoration:active_opacity"].floatValue = 1;
configValues["decoration:inactive_opacity"].floatValue = 1; configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 1; configValues["decoration:fullscreen_opacity"].floatValue = 1;
@@ -84,10 +88,12 @@ void CConfigManager::setDefaultVars() {
configValues["decoration:shadow_render_power"].intValue = 3; configValues["decoration:shadow_render_power"].intValue = 3;
configValues["decoration:shadow_ignore_window"].intValue = 1; configValues["decoration:shadow_ignore_window"].intValue = 1;
configValues["decoration:shadow_offset"].vecValue = Vector2D(); configValues["decoration:shadow_offset"].vecValue = Vector2D();
configValues["decoration:shadow_scale"].floatValue = 1.f;
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a; configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX; configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
configValues["decoration:dim_inactive"].intValue = 0; configValues["decoration:dim_inactive"].intValue = 0;
configValues["decoration:dim_strength"].floatValue = 0.5f; configValues["decoration:dim_strength"].floatValue = 0.5f;
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
configValues["dwindle:pseudotile"].intValue = 0; configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:col.group_border"].intValue = 0x66777700; configValues["dwindle:col.group_border"].intValue = 0x66777700;
@@ -103,6 +109,8 @@ void CConfigManager::setDefaultVars() {
configValues["master:new_is_master"].intValue = 1; configValues["master:new_is_master"].intValue = 1;
configValues["master:new_on_top"].intValue = 0; configValues["master:new_on_top"].intValue = 0;
configValues["master:no_gaps_when_only"].intValue = 0; configValues["master:no_gaps_when_only"].intValue = 0;
configValues["master:orientation"].strValue = "left";
configValues["master:inherit_fullscreen"].intValue = 1;
configValues["animations:enabled"].intValue = 1; configValues["animations:enabled"].intValue = 1;
configValues["animations:speed"].floatValue = 7.f; configValues["animations:speed"].floatValue = 7.f;
@@ -125,6 +133,7 @@ void CConfigManager::setDefaultVars() {
configValues["animations:workspaces"].intValue = 1; configValues["animations:workspaces"].intValue = 1;
configValues["input:sensitivity"].floatValue = 0.f; configValues["input:sensitivity"].floatValue = 0.f;
configValues["input:accel_profile"].strValue = STRVAL_EMPTY;
configValues["input:kb_file"].strValue = STRVAL_EMPTY; configValues["input:kb_file"].strValue = STRVAL_EMPTY;
configValues["input:kb_layout"].strValue = "us"; configValues["input:kb_layout"].strValue = "us";
configValues["input:kb_variant"].strValue = STRVAL_EMPTY; configValues["input:kb_variant"].strValue = STRVAL_EMPTY;
@@ -137,12 +146,18 @@ void CConfigManager::setDefaultVars() {
configValues["input:numlock_by_default"].intValue = 0; configValues["input:numlock_by_default"].intValue = 0;
configValues["input:force_no_accel"].intValue = 0; configValues["input:force_no_accel"].intValue = 0;
configValues["input:float_switch_override_focus"].intValue = 1; configValues["input:float_switch_override_focus"].intValue = 1;
configValues["input:left_handed"].intValue = 0;
configValues["input:scroll_method"].strValue = STRVAL_EMPTY;
configValues["input:scroll_button"].intValue = 0;
configValues["input:touchpad:natural_scroll"].intValue = 0; configValues["input:touchpad:natural_scroll"].intValue = 0;
configValues["input:touchpad:disable_while_typing"].intValue = 1; configValues["input:touchpad:disable_while_typing"].intValue = 1;
configValues["input:touchpad:clickfinger_behavior"].intValue = 0; configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
configValues["input:touchpad:middle_button_emulation"].intValue = 0; configValues["input:touchpad:middle_button_emulation"].intValue = 0;
configValues["input:touchpad:tap-to-click"].intValue = 1; configValues["input:touchpad:tap-to-click"].intValue = 1;
configValues["input:touchpad:drag_lock"].intValue = 0; configValues["input:touchpad:drag_lock"].intValue = 0;
configValues["input:touchpad:scroll_factor"].floatValue = 1.f;
configValues["input:touchdevice:transform"].intValue = 0;
configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY;
configValues["binds:pass_mouse_when_bound"].intValue = 0; configValues["binds:pass_mouse_when_bound"].intValue = 0;
configValues["binds:scroll_event_delay"].intValue = 300; configValues["binds:scroll_event_delay"].intValue = 300;
@@ -155,6 +170,8 @@ void CConfigManager::setDefaultVars() {
configValues["gestures:workspace_swipe_invert"].intValue = 1; configValues["gestures:workspace_swipe_invert"].intValue = 1;
configValues["gestures:workspace_swipe_min_speed_to_force"].intValue = 30; configValues["gestures:workspace_swipe_min_speed_to_force"].intValue = 30;
configValues["gestures:workspace_swipe_cancel_ratio"].floatValue = 0.5f; configValues["gestures:workspace_swipe_cancel_ratio"].floatValue = 0.5f;
configValues["gestures:workspace_swipe_create_new"].intValue = 1;
configValues["gestures:workspace_swipe_forever"].intValue = 0;
configValues["input:follow_mouse"].intValue = 1; configValues["input:follow_mouse"].intValue = 1;
@@ -165,6 +182,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
auto& cfgValues = deviceConfigs[dev]; auto& cfgValues = deviceConfigs[dev];
cfgValues["sensitivity"].floatValue = 0.f; cfgValues["sensitivity"].floatValue = 0.f;
cfgValues["accel_profile"].strValue = STRVAL_EMPTY;
cfgValues["kb_file"].strValue = STRVAL_EMPTY; cfgValues["kb_file"].strValue = STRVAL_EMPTY;
cfgValues["kb_layout"].strValue = "us"; cfgValues["kb_layout"].strValue = "us";
cfgValues["kb_variant"].strValue = STRVAL_EMPTY; cfgValues["kb_variant"].strValue = STRVAL_EMPTY;
@@ -180,6 +198,12 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
cfgValues["middle_button_emulation"].intValue = 0; cfgValues["middle_button_emulation"].intValue = 0;
cfgValues["tap-to-click"].intValue = 1; cfgValues["tap-to-click"].intValue = 1;
cfgValues["drag_lock"].intValue = 0; cfgValues["drag_lock"].intValue = 0;
cfgValues["left_handed"].intValue = 0;
cfgValues["scroll_method"].strValue = STRVAL_EMPTY;
cfgValues["scroll_button"].intValue = 0;
cfgValues["touch_transform"].intValue = 0;
cfgValues["touch_output"].strValue = STRVAL_EMPTY;
cfgValues["enabled"].intValue = 1; // only for mice / touchpads
} }
void CConfigManager::setDefaultAnimationVars() { void CConfigManager::setDefaultAnimationVars() {
@@ -296,20 +320,10 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
if (CONFIGENTRY->intValue != -INT64_MAX) { if (CONFIGENTRY->intValue != -INT64_MAX) {
try { try {
if (VALUE.find("0x") == 0) { CONFIGENTRY->intValue = configStringToInt(VALUE);
// Values with 0x are hex } catch (std::exception& e) {
const auto VALUEWITHOUTHEX = VALUE.substr(2);
CONFIGENTRY->intValue = stol(VALUEWITHOUTHEX, nullptr, 16);
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
CONFIGENTRY->intValue = 1;
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
CONFIGENTRY->intValue = 0;
}
else
CONFIGENTRY->intValue = stol(VALUE);
} catch (...) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str()); Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">."; parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
} }
} else if (CONFIGENTRY->floatValue != -__FLT_MAX__) { } else if (CONFIGENTRY->floatValue != -__FLT_MAX__) {
try { try {
@@ -342,62 +356,77 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str()); Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">."; parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
} }
} else if (CONFIGENTRY->data.get() != nullptr) {
switch (CONFIGENTRY->data->getDataType()) {
case CVD_TYPE_GRADIENT: {
CVarList varlist(VALUE, 0, ' ');
CGradientValueData* data = (CGradientValueData*)CONFIGENTRY->data.get();
data->m_vColors.clear();
for (auto& var : varlist) {
if (var.find("deg") != std::string::npos) {
// last arg
try {
data->m_fAngle = std::stoi(var.substr(0, var.find("deg"))) * (PI / 180.0); // radians
} catch (...) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">.";
}
break;
}
if (data->m_vColors.size() >= 10) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. Max colors in a gradient is 10.";
break;
}
try {
data->m_vColors.push_back(CColor(configStringToInt(var)) * (1.f / 255.f));
} catch (std::exception& e) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. " + e.what();
}
}
if (data->m_vColors.size() == 0) {
Debug::log(WARN, "Error reading value of %s", COMMAND.c_str());
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">. No colors provided.";
data->m_vColors.push_back(0); // transparent
}
break;
}
default: {
UNREACHABLE();
}
}
}
if (COMMAND == "decoration:screen_shader") {
const auto PATH = absolutePath(VALUE, configCurrentPath);
configPaths.push_back(PATH);
struct stat fileStat;
int err = stat(PATH.c_str(), &fileStat);
if (err != 0) {
Debug::log(WARN, "Error at ticking config at %s, error %i: %s", PATH.c_str(), err, strerror(err));
return;
}
configModifyTimes[PATH] = fileStat.st_mtime;
} }
} }
void CConfigManager::handleRawExec(const std::string& command, const std::string& args) { void CConfigManager::handleRawExec(const std::string& command, const std::string& args) {
// Exec in the background dont wait for it. // Exec in the background dont wait for it.
g_pKeybindManager->spawn(args);
std::string toExec = args;
if (g_pXWaylandManager->m_sWLRXWayland)
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + toExec;
else
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " " + toExec;
Debug::log(LOG, "Config executing %s", toExec.c_str());
int socket[2];
if (pipe(socket) != 0) {
Debug::log(LOG, "Unable to create pipe for fork");
}
pid_t child, grandchild;
child = fork();
if (child < 0) {
close(socket[0]);
close(socket[1]);
Debug::log(LOG, "Fail to create the first fork");
return;
}
if (child == 0) {
// run in child
grandchild = fork();
if (grandchild == 0) {
// run in grandchild
close(socket[0]);
close(socket[1]);
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
// exit grandchild
_exit(0);
}
close(socket[0]);
write(socket[1], &grandchild, sizeof(grandchild));
close(socket[1]);
// exit child
_exit(0);
}
// run in parent
close(socket[1]);
read(socket[0], &grandchild, sizeof(grandchild));
close(socket[0]);
// clear child and leave child to init
waitpid(child, NULL, 0);
if (child < 0) {
Debug::log(LOG, "Fail to create the second fork");
return;
}
Debug::log(LOG, "Process created with pid %d", grandchild);
} }
void CConfigManager::handleMonitor(const std::string& command, const std::string& args) { void CConfigManager::handleMonitor(const std::string& command, const std::string& args) {
@@ -488,6 +517,9 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
if (ARGS[argno] == "mirror") { if (ARGS[argno] == "mirror") {
newrule.mirrorOf = ARGS[argno + 1]; newrule.mirrorOf = ARGS[argno + 1];
argno++; argno++;
} else if (ARGS[argno] == "bitdepth") {
newrule.enable10bit = ARGS[argno + 1] == "10";
argno++;
} else { } else {
Debug::log(ERR, "Config error: invalid monitor syntax"); Debug::log(ERR, "Config error: invalid monitor syntax");
parseError = "invalid syntax at \"" + ARGS[argno] + "\""; parseError = "invalid syntax at \"" + ARGS[argno] + "\"";
@@ -705,18 +737,28 @@ bool windowRuleValid(const std::string& RULE) {
&& RULE.find("opacity") != 0 && RULE.find("opacity") != 0
&& RULE.find("move") != 0 && RULE.find("move") != 0
&& RULE.find("size") != 0 && RULE.find("size") != 0
&& RULE.find("minsize") != 0
&& RULE.find("maxsize") != 0
&& RULE.find("pseudo") != 0 && RULE.find("pseudo") != 0
&& RULE.find("monitor") != 0 && RULE.find("monitor") != 0
&& RULE.find("idleinhibit") != 0
&& RULE != "nofocus" && RULE != "nofocus"
&& RULE != "noblur" && RULE != "noblur"
&& RULE != "noshadow"
&& RULE != "noborder"
&& RULE != "center" && RULE != "center"
&& RULE != "opaque" && RULE != "opaque"
&& RULE != "forceinput" && RULE != "forceinput"
&& RULE != "fullscreen" && RULE != "fullscreen"
&& RULE != "nofullscreenrequest"
&& RULE != "nomaxsize"
&& RULE != "pin" && RULE != "pin"
&& RULE != "noanim"
&& RULE != "windowdance"
&& RULE.find("animation") != 0 && RULE.find("animation") != 0
&& RULE.find("rounding") != 0 && RULE.find("rounding") != 0
&& RULE.find("workspace") != 0); && RULE.find("workspace") != 0
&& RULE.find("bordercolor") != 0);
} }
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) { void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
@@ -728,6 +770,13 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
return; return;
} }
if (RULE == "unset") {
std::erase_if(m_dWindowRules, [&] (const SWindowRule& other) {
return other.szValue == VALUE;
});
return;
}
// verify we support a rule // verify we support a rule
if (!windowRuleValid(RULE)) { if (!windowRuleValid(RULE)) {
Debug::log(ERR, "Invalid rule found: %s", RULE.c_str()); Debug::log(ERR, "Invalid rule found: %s", RULE.c_str());
@@ -742,7 +791,7 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
const auto RULE = value.substr(0, value.find_first_of(",")); const auto RULE = value.substr(0, value.find_first_of(","));
const auto VALUE = value.substr(value.find_first_of(",") + 1); const auto VALUE = value.substr(value.find_first_of(",") + 1);
if (!windowRuleValid(RULE)) { if (!windowRuleValid(RULE) && RULE != "unset") {
Debug::log(ERR, "Invalid rulev2 found: %s", RULE.c_str()); Debug::log(ERR, "Invalid rulev2 found: %s", RULE.c_str());
parseError = "Invalid rulev2 found: " + RULE; parseError = "Invalid rulev2 found: " + RULE;
return; return;
@@ -758,8 +807,12 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
const auto CLASSPOS = VALUE.find("class:"); const auto CLASSPOS = VALUE.find("class:");
const auto X11POS = VALUE.find("xwayland:"); const auto X11POS = VALUE.find("xwayland:");
const auto FLOATPOS = VALUE.find("floating:"); const auto FLOATPOS = VALUE.find("floating:");
const auto FULLSCREENPOS = VALUE.find("fullscreen:");
const auto PINNEDPOS = VALUE.find("pinned:");
if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && X11POS == std::string::npos && FLOATPOS == std::string::npos) { if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos &&
X11POS == std::string::npos && FLOATPOS == std::string::npos &&
FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos) {
Debug::log(ERR, "Invalid rulev2 syntax: %s", VALUE.c_str()); Debug::log(ERR, "Invalid rulev2 syntax: %s", VALUE.c_str());
parseError = "Invalid rulev2 syntax: " + VALUE; parseError = "Invalid rulev2 syntax: " + VALUE;
return; return;
@@ -774,6 +827,8 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
if (CLASSPOS > pos && CLASSPOS < min) min = CLASSPOS; if (CLASSPOS > pos && CLASSPOS < min) min = CLASSPOS;
if (X11POS > pos && X11POS < min) min = X11POS; if (X11POS > pos && X11POS < min) min = X11POS;
if (FLOATPOS > pos && FLOATPOS < min) min = FLOATPOS; if (FLOATPOS > pos && FLOATPOS < min) min = FLOATPOS;
if (FULLSCREENPOS > pos && FULLSCREENPOS < min) min = FULLSCREENPOS;
if (PINNEDPOS > pos && PINNEDPOS < min) min = PINNEDPOS;
result = result.substr(0, min - pos); result = result.substr(0, min - pos);
@@ -801,13 +856,56 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0; rule.bFloating = extract(FLOATPOS + 9) == "1" ? 1 : 0;
} }
if (FULLSCREENPOS != std::string::npos) {
rule.bFullscreen = extract(FULLSCREENPOS + 11) == "1" ? 1 : 0;
}
if (PINNEDPOS != std::string::npos) {
rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0;
}
if (RULE == "unset") {
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
if (!other.v2) {
return other.szClass == rule.szClass && !rule.szClass.empty();
} else {
if (!rule.szClass.empty() && rule.szClass != other.szClass) {
return false;
}
if (!rule.szTitle.empty() && rule.szTitle != other.szTitle) {
return false;
}
if (rule.bX11 != -1 && rule.bX11 != other.bX11) {
return false;
}
if (rule.bFloating != -1 && rule.bFloating != other.bFloating) {
return false;
}
if (rule.bFullscreen != -1 && rule.bFullscreen != other.bFullscreen) {
return false;
}
if (rule.bPinned != -1 && rule.bPinned != other.bPinned) {
return false;
}
return true;
}
});
return;
}
m_dWindowRules.push_back(rule); m_dWindowRules.push_back(rule);
} }
void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) { void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
if (value.find("remove,") == 0) { if (value.find("remove,") == 0) {
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7)); const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
m_dBlurLSNamespaces.erase(std::remove(m_dBlurLSNamespaces.begin(), m_dBlurLSNamespaces.end(), TOREMOVE)); std::erase_if(m_dBlurLSNamespaces, [&] (const auto& other) { return other == TOREMOVE; });
return; return;
} }
@@ -905,6 +1003,8 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
currentCategory = ""; currentCategory = "";
} }
int needsLayoutRecalc = COMMAND == "monitor"; // 0 - no, 1 - yes, 2 - maybe
if (COMMAND == "exec") { if (COMMAND == "exec") {
if (isFirstLaunch) { if (isFirstLaunch) {
firstExecRequests.push_back(VALUE); firstExecRequests.push_back(VALUE);
@@ -928,16 +1028,22 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
else if (COMMAND == "submap") handleSubmap(COMMAND, VALUE); else if (COMMAND == "submap") handleSubmap(COMMAND, VALUE);
else if (COMMAND == "blurls") handleBlurLS(COMMAND, VALUE); else if (COMMAND == "blurls") handleBlurLS(COMMAND, VALUE);
else if (COMMAND == "wsbind") handleBindWS(COMMAND, VALUE); else if (COMMAND == "wsbind") handleBindWS(COMMAND, VALUE);
else else {
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE); configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
needsLayoutRecalc = 2;
}
if (dynamic) { if (dynamic) {
std::string retval = parseError; std::string retval = parseError;
parseError = ""; parseError = "";
// invalidate layouts jic // invalidate layouts if they changed
for (auto& m : g_pCompositor->m_vMonitors) if (needsLayoutRecalc) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); if (needsLayoutRecalc == 1 || COMMAND.contains("gaps_") || COMMAND.find("dwindle:") == 0 || COMMAND.find("master:") == 0) {
for (auto& m : g_pCompositor->m_vMonitors)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
}
}
// Update window border colors // Update window border colors
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -967,13 +1073,26 @@ void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equals
void CConfigManager::parseLine(std::string& line) { void CConfigManager::parseLine(std::string& line) {
// first check if its not a comment // first check if its not a comment
const auto COMMENTSTART = line.find_first_of('#'); if (line[0] == '#')
if (COMMENTSTART == 0)
return; return;
// now, cut the comment off // now, cut the comment off. ## is an escape.
if (COMMENTSTART != std::string::npos) for (long unsigned int i = 1; i < line.length(); ++i) {
line = line.substr(0, COMMENTSTART); if (line[i] == '#') {
if (i + 1 < line.length() && line[i + 1] != '#') {
line = line.substr(0, i);
break; // no need to parse more
}
i++;
}
}
size_t startPos = 0;
while ((startPos = line.find("##", startPos)) != std::string::npos && startPos < line.length() - 1 && startPos > 0) {
line.replace(startPos, 2, "#");
startPos++;
}
// remove shit at the beginning // remove shit at the beginning
while (line[0] == ' ' || line[0] == '\t') { while (line[0] == ' ' || line[0] == '\t') {
@@ -1124,18 +1243,15 @@ void CConfigManager::loadConfigLoadVars() {
// Update the keyboard layout to the cfg'd one if this is not the first launch // 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->setKeyboardLayout();
g_pInputManager->setMouseConfigs(); g_pInputManager->setPointerConfigs();
g_pInputManager->setTouchDeviceConfigs();
} }
// Calculate the internal vars // Calculate the internal vars
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue); configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue);
const auto DAMAGETRACKINGMODE = g_pHyprRenderer->damageTrackingModeFromStr(configValues["general:damage_tracking"].strValue);
if (DAMAGETRACKINGMODE != DAMAGE_TRACKING_INVALID) if (!isFirstLaunch)
configValues["general:damage_tracking_internal"].intValue = DAMAGETRACKINGMODE; g_pHyprOpenGL->m_bReloadScreenShader = true;
else {
parseError = "invalid value for general:damage_tracking, supported: full, monitor, none";
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_NONE;
}
// parseError will be displayed next frame // parseError will be displayed next frame
if (parseError != "") if (parseError != "")
@@ -1150,10 +1266,10 @@ void CConfigManager::loadConfigLoadVars() {
// and they'll be taken care of in the newMonitor event // and they'll be taken care of in the newMonitor event
// ignore if nomonitorreload is set // ignore if nomonitorreload is set
if (!isFirstLaunch && !m_bNoMonitorReload) { if (!isFirstLaunch && !m_bNoMonitorReload) {
m_bWantsMonitorReload = true;
// check // check
performMonitorReload();
ensureDPMS(); ensureDPMS();
ensureVRR();
} }
// Update window border colors // Update window border colors
@@ -1220,13 +1336,10 @@ SConfigValue CConfigManager::getConfigValueSafe(const std::string& val) {
SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val) { SConfigValue CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val) {
std::lock_guard<std::mutex> lg(configmtx); std::lock_guard<std::mutex> lg(configmtx);
auto devcopy = dev; const auto it = deviceConfigs.find(dev);
std::replace(devcopy.begin(), devcopy.end(), ' ', '-');
const auto it = deviceConfigs.find(devcopy);
if (it == deviceConfigs.end()) { if (it == deviceConfigs.end()) {
Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", devcopy.c_str()); Debug::log(ERR, "getConfigValueSafeDevice: No device config for %s found???", dev.c_str());
return SConfigValue(); return SConfigValue();
} }
@@ -1294,11 +1407,11 @@ void CConfigManager::setString(std::string v, std::string val) {
configValues[v].strValue = val; configValues[v].strValue = val;
} }
SMonitorRule CConfigManager::getMonitorRuleFor(std::string name) { SMonitorRule CConfigManager::getMonitorRuleFor(std::string name, std::string displayName) {
SMonitorRule* found = nullptr; SMonitorRule* found = nullptr;
for (auto& r : m_dMonitorRules) { for (auto& r : m_dMonitorRules) {
if (r.name == name) { if (r.name == name || (r.name.find("desc:") == 0 && (r.name.substr(5) == displayName || r.name.substr(5) == removeBeginEndSpacesTabs(displayName.substr(0, displayName.find_first_of('(')))))) {
found = &r; found = &r;
break; break;
} }
@@ -1380,6 +1493,16 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
if (pWindow->m_bIsFloating != rule.bFloating) if (pWindow->m_bIsFloating != rule.bFloating)
continue; continue;
} }
if (rule.bFullscreen != -1) {
if (pWindow->m_bIsFullscreen != rule.bFullscreen)
continue;
}
if (rule.bPinned != -1) {
if (pWindow->m_bPinned != rule.bPinned)
continue;
}
} catch (...) { } catch (...) {
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str()); Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
continue; continue;
@@ -1392,6 +1515,19 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
returns.push_back(rule); returns.push_back(rule);
} }
const uint64_t PID = pWindow->getPID();
bool anyExecFound = false;
for (auto& er : execRequestedRules) {
if (er.iPid == PID) {
returns.push_back({er.szRule, "execRule"});
anyExecFound = true;
}
}
if (anyExecFound) // remove exec rules to unclog searches in the future, why have the garbage here.
execRequestedRules.erase(std::remove_if(execRequestedRules.begin(), execRequestedRules.end(), [&](const SExecRequestedRule& other) { return other.iPid == PID; }));
return returns; return returns;
} }
@@ -1409,7 +1545,8 @@ void CConfigManager::dispatchExecOnce() {
// set input, fixes some certain issues // set input, fixes some certain issues
g_pInputManager->setKeyboardLayout(); g_pInputManager->setKeyboardLayout();
g_pInputManager->setMouseConfigs(); g_pInputManager->setPointerConfigs();
g_pInputManager->setTouchDeviceConfigs();
// set ws names again // set ws names again
for (auto& ws : g_pCompositor->m_vWorkspaces) { for (auto& ws : g_pCompositor->m_vWorkspaces) {
@@ -1422,22 +1559,25 @@ void CConfigManager::performMonitorReload() {
bool overAgain = false; bool overAgain = false;
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
auto rule = getMonitorRuleFor(m->szName); auto rule = getMonitorRuleFor(m->szName, m->output->description ? m->output->description : "");
// ensure mirror
m->setMirror(rule.mirrorOf);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) {
overAgain = true; overAgain = true;
break; break;
} }
// ensure mirror
m->setMirror(rule.mirrorOf);
g_pHyprRenderer->arrangeLayersForMonitor(m->ID); g_pHyprRenderer->arrangeLayersForMonitor(m->ID);
} }
if (overAgain) if (overAgain)
performMonitorReload(); performMonitorReload();
if (!g_pCompositor->m_vMonitors.empty()) // reset unsafe state if we have monitors
g_pCompositor->m_bUnsafeState = false;
m_bWantsMonitorReload = false; m_bWantsMonitorReload = false;
} }
@@ -1475,7 +1615,7 @@ bool CConfigManager::shouldBlurLS(const std::string& ns) {
void CConfigManager::ensureDPMS() { void CConfigManager::ensureDPMS() {
for (auto& rm : g_pCompositor->m_vRealMonitors) { for (auto& rm : g_pCompositor->m_vRealMonitors) {
auto rule = getMonitorRuleFor(rm->szName); auto rule = getMonitorRuleFor(rm->szName, rm->output->description ? rm->output->description : "");
if (rule.disabled == rm->m_bEnabled) { if (rule.disabled == rm->m_bEnabled) {
rm->m_pThisWrap = &rm; rm->m_pThisWrap = &rm;
@@ -1484,6 +1624,49 @@ void CConfigManager::ensureDPMS() {
} }
} }
void CConfigManager::ensureVRR(CMonitor* pMonitor) {
static auto *const PNOVRR = &getConfigValuePtr("misc:no_vfr")->intValue;
auto ensureVRRForDisplay = [&](CMonitor* m) -> void {
if (!*PNOVRR && !m->vrrActive) {
// Adaptive sync (VRR)
wlr_output_enable_adaptive_sync(m->output, 1);
if (!wlr_output_test(m->output)) {
Debug::log(LOG, "Pending output %s does not accept VRR.", m->output->name);
wlr_output_enable_adaptive_sync(m->output, 0);
}
if (!wlr_output_commit(m->output)) {
Debug::log(ERR, "Couldn't commit output %s in ensureVRR -> true", m->output->name);
}
m->vrrActive = true;
Debug::log(LOG, "VRR ensured on %s -> true", m->output->name);
} else if (*PNOVRR && m->vrrActive) {
wlr_output_enable_adaptive_sync(m->output, 0);
if (!wlr_output_commit(m->output)) {
Debug::log(ERR, "Couldn't commit output %s in ensureVRR -> false", m->output->name);
}
m->vrrActive = false;
Debug::log(LOG, "VRR ensured on %s -> false", m->output->name);
}
};
if (pMonitor) {
ensureVRRForDisplay(pMonitor);
return;
}
for (auto& m : g_pCompositor->m_vMonitors) {
ensureVRRForDisplay(m.get());
}
}
SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::string& name) { SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::string& name) {
return &animationConfig[name]; return &animationConfig[name];
} }
@@ -1491,6 +1674,8 @@ SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::
void CConfigManager::addParseError(const std::string& err) { void CConfigManager::addParseError(const std::string& err) {
if (parseError == "") if (parseError == "")
parseError = err; parseError = err;
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255));
} }
CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) { CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {
@@ -1504,3 +1689,23 @@ CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {
return nullptr; return nullptr;
} }
std::string CConfigManager::getBoundMonitorStringForWS(std::string wsname) {
for (auto& [ws, mon] : boundWorkspaces) {
const auto WSNAME = ws.find("name:") == 0 ? ws.substr(5) : ws;
if (WSNAME == wsname) {
return mon;
}
}
return "";
}
void CConfigManager::addExecRule(SExecRequestedRule rule) {
execRequestedRules.push_back(rule);
}
ICustomConfigValueData::~ICustomConfigValueData() {
; // empty
}

View File

@@ -13,6 +13,7 @@
#include "../Window.hpp" #include "../Window.hpp"
#include "defaultConfig.hpp" #include "defaultConfig.hpp"
#include "ConfigDataValues.hpp"
#define STRVAL_EMPTY "[[EMPTY]]" #define STRVAL_EMPTY "[[EMPTY]]"
@@ -24,6 +25,7 @@ struct SConfigValue {
float floatValue = -__FLT_MAX__; float floatValue = -__FLT_MAX__;
std::string strValue = ""; std::string strValue = "";
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__); Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
std::shared_ptr<ICustomConfigValueData> data;
bool set = false; // used for device configs bool set = false; // used for device configs
}; };
@@ -38,6 +40,7 @@ struct SMonitorRule {
bool disabled = false; bool disabled = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
std::string mirrorOf = ""; std::string mirrorOf = "";
bool enable10bit = false;
}; };
struct SMonitorAdditionalReservedArea { struct SMonitorAdditionalReservedArea {
@@ -47,17 +50,6 @@ struct SMonitorAdditionalReservedArea {
int right = 0; int right = 0;
}; };
struct SWindowRule {
std::string szRule;
std::string szValue;
bool v2 = false;
std::string szTitle;
std::string szClass;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
};
struct SAnimationPropertyConfig { struct SAnimationPropertyConfig {
bool overriden = true; bool overriden = true;
@@ -70,14 +62,19 @@ struct SAnimationPropertyConfig {
SAnimationPropertyConfig* pParentAnimation = nullptr; SAnimationPropertyConfig* pParentAnimation = nullptr;
}; };
struct SExecRequestedRule {
std::string szRule = "";
uint64_t iPid = 0;
};
class CVarList { class CVarList {
public: public:
CVarList(const std::string& in, long unsigned int lastArgNo = 0) { CVarList(const std::string& in, long unsigned int lastArgNo = 0, const char separator = ',') {
std::string curitem = ""; std::string curitem = "";
std::string argZ = in; std::string argZ = in;
auto nextItem = [&]() { auto nextItem = [&]() {
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(','); auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(separator);
if (idx != std::string::npos) { if (idx != std::string::npos) {
curitem = argZ.substr(0, idx); curitem = argZ.substr(0, idx);
@@ -98,7 +95,7 @@ public:
~CVarList() = default; ~CVarList() = default;
int size() const { size_t size() const {
return m_vArgs.size(); return m_vArgs.size();
} }
@@ -108,7 +105,13 @@ public:
return m_vArgs[idx]; return m_vArgs[idx];
} }
private: // for range-based loops
std::vector<std::string>::iterator begin() { return m_vArgs.begin(); }
std::vector<std::string>::const_iterator begin() const { return m_vArgs.begin(); }
std::vector<std::string>::iterator end() { return m_vArgs.end(); }
std::vector<std::string>::const_iterator end() const { return m_vArgs.end(); }
private:
std::vector<std::string> m_vArgs; std::vector<std::string> m_vArgs;
}; };
@@ -135,9 +138,10 @@ public:
SConfigValue* getConfigValuePtr(std::string); SConfigValue* getConfigValuePtr(std::string);
SConfigValue* getConfigValuePtrSafe(std::string); SConfigValue* getConfigValuePtrSafe(std::string);
SMonitorRule getMonitorRuleFor(std::string); SMonitorRule getMonitorRuleFor(std::string, std::string displayName = "");
CMonitor* getBoundMonitorForWS(std::string); CMonitor* getBoundMonitorForWS(std::string);
std::string getBoundMonitorStringForWS(std::string);
std::vector<SWindowRule> getMatchingRules(CWindow*); std::vector<SWindowRule> getMatchingRules(CWindow*);
@@ -151,6 +155,7 @@ public:
bool m_bForceReload = false; bool m_bForceReload = false;
bool m_bNoMonitorReload = false; bool m_bNoMonitorReload = false;
void ensureDPMS(); void ensureDPMS();
void ensureVRR(CMonitor* pMonitor = nullptr);
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false); std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
@@ -158,6 +163,8 @@ public:
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&); SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
void addExecRule(SExecRequestedRule);
std::string configCurrentPath; std::string configCurrentPath;
private: private:
@@ -177,6 +184,8 @@ private:
std::vector<std::pair<std::string, std::string>> boundWorkspaces; std::vector<std::pair<std::string, std::string>> boundWorkspaces;
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
bool isFirstLaunch = true; // For exec-once bool isFirstLaunch = true; // For exec-once
std::deque<SMonitorRule> m_dMonitorRules; std::deque<SMonitorRule> m_dMonitorRules;

View File

@@ -9,121 +9,160 @@ PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS. OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
######################################################################################## ########################################################################################
# #
# Please note not all available settings / options are set here. # Please note not all available settings / options are set here.
# For a full list, see the wiki (basic and advanced configuring) # For a full list, see the wiki
# #
autogenerated=1 # remove this line to get rid of the warning on top. autogenerated = 1 # remove this line to remove the warning
# See https://wiki.hyprland.org/Configuring/Monitors/
monitor=,preferred,auto,1 monitor=,preferred,auto,1
input {
kb_file=
kb_layout=
kb_variant=
kb_model=
kb_options=
kb_rules=
follow_mouse=1 # See https://wiki.hyprland.org/Configuring/Keywords/ for more
# Execute your favorite apps at launch
# exec-once = waybar & hyprpaper & firefox
# Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
input {
kb_layout = us
kb_variant =
kb_model =
kb_options =
kb_rules =
follow_mouse = 1
touchpad { touchpad {
natural_scroll=no natural_scroll = no
} }
sensitivity=0 # -1.0 - 1.0, 0 means no modification. sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
} }
general { general {
main_mod=SUPER # See https://wiki.hyprland.org/Configuring/Variables/ for more
gaps_in=5 gaps_in = 5
gaps_out=20 gaps_out = 20
border_size=2 border_size = 2
col.active_border=0x66ee1111 col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
col.inactive_border=0x66333333 col.inactive_border = rgba(595959aa)
apply_sens_to_raw=0 # whether to apply the sensitivity to raw input (e.g. used by games where you aim using your mouse) layout = dwindle
damage_tracking=full # leave it on full unless you hate your GPU and want to make it suffer
} }
decoration { decoration {
rounding=10 # See https://wiki.hyprland.org/Configuring/Variables/ for more
blur=1
blur_size=3 # minimum 1 rounding = 10
blur_passes=1 # minimum 1 blur = yes
blur_new_optimizations=1 blur_size = 3
blur_passes = 1
blur_new_optimizations = on
drop_shadow = yes
shadow_range = 4
shadow_render_power = 3
col.shadow = rgba(1a1a1aee)
} }
animations { animations {
enabled=1 enabled = yes
animation=windows,1,7,default
animation=border,1,10,default # Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
animation=fade,1,10,default
animation=workspaces,1,6,default bezier = myBezier, 0.05, 0.9, 0.1, 1.05
animation = windows, 1, 7, myBezier
animation = windowsOut, 1, 7, default, popin 80%
animation = border, 1, 10, default
animation = fade, 1, 7, default
animation = workspaces, 1, 6, default
} }
dwindle { dwindle {
pseudotile=0 # enable pseudotiling on dwindle # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
pseudotile = yes # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = yes # you probably want this
}
master {
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
new_is_master = true
} }
gestures { gestures {
workspace_swipe=no # See https://wiki.hyprland.org/Configuring/Variables/ for more
workspace_swipe = off
} }
# example window rules # Example per-device config
# for windows named/classed as abc and xyz # See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
#windowrule=move 69 420,abc device:epic mouse V1 {
#windowrule=size 420 69,abc sensitivity = -0.5
#windowrule=tile,xyz }
#windowrule=float,abc
#windowrule=pseudo,abc
#windowrule=monitor 0,xyz
# some nice mouse binds # Example windowrule v1
bindm=SUPER,mouse:272,movewindow # windowrule = float, ^(kitty)$
bindm=SUPER,mouse:273,resizewindow # Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# example binds
bind=SUPER,Q,exec,kitty
bind=SUPER,RETURN,exec,alacritty
bind=SUPER,C,killactive,
bind=SUPER,M,exit,
bind=SUPER,E,exec,dolphin
bind=SUPER,V,togglefloating,
bind=SUPER,R,exec,wofi --show drun -o DP-3
bind=SUPER,P,pseudo,
bind=SUPER,left,movefocus,l # See https://wiki.hyprland.org/Configuring/Keywords/ for more
bind=SUPER,right,movefocus,r $mainMod = SUPER
bind=SUPER,up,movefocus,u
bind=SUPER,down,movefocus,d
bind=SUPER,1,workspace,1 # Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind=SUPER,2,workspace,2 bind = $mainMod, Q, exec, kitty
bind=SUPER,3,workspace,3 bind = $mainMod, C, killactive,
bind=SUPER,4,workspace,4 bind = $mainMod, M, exit,
bind=SUPER,5,workspace,5 bind = $mainMod, E, exec, dolphin
bind=SUPER,6,workspace,6 bind = $mainMod, V, togglefloating,
bind=SUPER,7,workspace,7 bind = $mainMod, R, exec, wofi --show drun
bind=SUPER,8,workspace,8 bind = $mainMod, P, pseudo, # dwindle
bind=SUPER,9,workspace,9 bind = $mainMod, J, togglesplit, # dwindle
bind=SUPER,0,workspace,10
bind=ALT,1,movetoworkspace,1 # Move focus with mainMod + arrow keys
bind=ALT,2,movetoworkspace,2 bind = $mainMod, left, movefocus, l
bind=ALT,3,movetoworkspace,3 bind = $mainMod, right, movefocus, r
bind=ALT,4,movetoworkspace,4 bind = $mainMod, up, movefocus, u
bind=ALT,5,movetoworkspace,5 bind = $mainMod, down, movefocus, d
bind=ALT,6,movetoworkspace,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 # Switch workspaces with mainMod + [0-9]
bind=SUPER,mouse_up,workspace,e-1 bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
# Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1
# Move/resize windows with mainMod + LMB/RMB and dragging
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
)#"; )#";

View File

@@ -23,6 +23,7 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
R"#({ R"#({
"id": %i, "id": %i,
"name": "%s", "name": "%s",
"description": "%s",
"width": %i, "width": %i,
"height": %i, "height": %i,
"refreshRate": %f, "refreshRate": %f,
@@ -35,10 +36,12 @@ R"#({
"reserved": [%i, %i, %i, %i], "reserved": [%i, %i, %i, %i],
"scale": %.2f, "scale": %.2f,
"transform": %i, "transform": %i,
"focused": %s "focused": %s,
"dpmsStatus": %s
},)#", },)#",
m->ID, m->ID,
escapeJSONStrings(m->szName).c_str(), escapeJSONStrings(m->szName).c_str(),
escapeJSONStrings(m->output->description ? m->output->description : "").c_str(),
(int)m->vecPixelSize.x, (int)m->vecPixelSize.y, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y,
m->refreshRate, m->refreshRate,
(int)m->vecPosition.x, (int)m->vecPosition.y, (int)m->vecPosition.x, (int)m->vecPosition.y,
@@ -46,7 +49,8 @@ R"#({
(int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y,
m->scale, m->scale,
(int)m->transform, (int)m->transform,
(m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false") (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false")
); );
} }
@@ -56,22 +60,45 @@ R"#({
result += "]"; result += "]";
} else { } else {
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\tfocused: %s\n\n", result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tdescription: %s\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\tfocused: %s\n\tdpmsStatus: %i\n\n",
m->szName.c_str(), m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName.c_str(), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no")); m->szName.c_str(), m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, (m->output->description ? m->output->description : ""), 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"), (int)m->dpmsStatus);
} }
} }
return result; return result;
} }
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) { static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
std::string result = ""; const bool isJson = format == HyprCtl::FORMAT_JSON;
if (format == HyprCtl::FORMAT_JSON) { if (g_pLayoutManager->getCurrentLayout()->getLayoutName() != "dwindle")
result += "["; return isJson ? "" : "0";
for (auto& w : g_pCompositor->m_vWindows) { SLayoutMessageHeader header;
if (w->m_bIsMapped) { header.pWindow = w;
result += getFormat( const auto groupMembers = std::any_cast<std::deque<CWindow*>>(g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "groupinfo"));
if (groupMembers.empty())
return isJson ? "" : "0";
const auto comma = isJson ? ", " : ",";
const auto fmt = isJson ? "\"0x%x\"" : "%x";
std::ostringstream result;
bool first = true;
for (auto& gw : groupMembers) {
if (first)
first = false;
else
result << comma;
result << getFormat(fmt, gw);
}
return result.str();
}
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
if (format == HyprCtl::FORMAT_JSON) {
return getFormat(
R"#({ R"#({
"address": "0x%x", "address": "0x%x",
"at": [%i, %i], "at": [%i, %i],
@@ -88,22 +115,40 @@ R"#({
"xwayland": %s, "xwayland": %s,
"pinned": %s, "pinned": %s,
"fullscreen": %s, "fullscreen": %s,
"fullscreenMode": %i "fullscreenMode": %i,
"grouped": [%s],
"swallowing": %s
},)#", },)#",
w.get(), w,
(int)w->m_vRealPosition.vec().x, (int)w->m_vRealPosition.vec().y, (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
(int)w->m_vRealSize.vec().x, (int)w->m_vRealSize.vec().y, (int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y,
w->m_iWorkspaceID, escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))).c_str(), w->m_iWorkspaceID, escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))).c_str(),
((int)w->m_bIsFloating == 1 ? "true" : "false"), ((int)w->m_bIsFloating == 1 ? "true" : "false"),
w->m_iMonitorID, w->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(), escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w)).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(), escapeJSONStrings(g_pXWaylandManager->getTitle(w)).c_str(),
w->getPID(), w->getPID(),
((int)w->m_bIsX11 == 1 ? "true" : "false"), ((int)w->m_bIsX11 == 1 ? "true" : "false"),
(w->m_bPinned ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
(w->m_bIsFullscreen ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0) (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
getGroupedData(w, format).c_str(),
(w->m_pSwallowed ? getFormat("\"0x%x\"", w->m_pSwallowed).c_str() : "null")
); );
} 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\tpinned: %i\n\tfullscreen: %i\n\tfullscreenmode: %i\n\tgrouped: %s\n\tswallowing: %x\n\n",
w, w->m_szTitle.c_str(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y, (int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().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).c_str(), g_pXWaylandManager->getTitle(w).c_str(), w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0), getGroupedData(w, format).c_str(), w->m_pSwallowed);
}
}
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
result += "[";
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped) {
result += getWindowData(w.get(), format);
} }
} }
@@ -115,9 +160,7 @@ R"#({
} else { } else {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped) { 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\tpinned: %i\n\tfullscreen: %i\n\tfullscreenmode: %i\n\n", result += getWindowData(w.get(), format);
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, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0));
} }
} }
} }
@@ -172,38 +215,12 @@ std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!g_pCompositor->windowValidMapped(PWINDOW))
return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid"; return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid";
if (format == HyprCtl::FORMAT_JSON) { auto result = getWindowData(PWINDOW, format);
return getFormat(
R"#({ if (format == HyprCtl::FORMAT_JSON)
"address": "0x%x", result.pop_back();
"at": [%i, %i],
"size": [%i, %i], return result;
"workspace": {
"id": %i,
"name": "%s"
},
"floating": %s,
"monitor": %i,
"class": "%s",
"title": "%s",
"pid": %i,
"xwayland": %s
})#",
PWINDOW,
(int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y,
(int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y,
PWINDOW->m_iWorkspaceID, escapeJSONStrings(PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName).c_str(),
((int)PWINDOW->m_bIsFloating == 1 ? "true" : "false"),
PWINDOW->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(),
PWINDOW->getPID(),
((int)PWINDOW->m_bIsX11 == 1 ? "true" : "false")
);
} else {
return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\n",
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(HyprCtl::eHyprCtlOutputFormat format) { std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
@@ -304,7 +321,7 @@ R"#( {
"defaultSpeed": %f "defaultSpeed": %f
},)#", },)#",
&m, &m,
escapeJSONStrings(m.mouse->name).c_str(), escapeJSONStrings(m.name).c_str(),
wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f
); );
} }
@@ -329,7 +346,7 @@ R"#( {
"main": %s "main": %s
},)#", },)#",
&k, &k,
escapeJSONStrings(k.keyboard->name).c_str(), escapeJSONStrings(k.name).c_str(),
escapeJSONStrings(k.currentRules.rules).c_str(), escapeJSONStrings(k.currentRules.rules).c_str(),
escapeJSONStrings(k.currentRules.model).c_str(), escapeJSONStrings(k.currentRules.model).c_str(),
escapeJSONStrings(k.currentRules.layout).c_str(), escapeJSONStrings(k.currentRules.layout).c_str(),
@@ -358,7 +375,7 @@ R"#( {
},)#", },)#",
&d, &d,
d.pTabletParent, d.pTabletParent,
escapeJSONStrings(d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "").c_str() escapeJSONStrings(d.pTabletParent ? d.pTabletParent->name : "").c_str()
); );
} }
@@ -369,7 +386,7 @@ R"#( {
"name": "%s" "name": "%s"
},)#", },)#",
&d, &d,
escapeJSONStrings(d.wlrDevice ? d.wlrDevice->name : "").c_str() escapeJSONStrings(d.name).c_str()
); );
} }
@@ -393,6 +410,24 @@ R"#( {
for (auto& d : g_pInputManager->m_lTouchDevices) { for (auto& d : g_pInputManager->m_lTouchDevices) {
result += getFormat( result += getFormat(
R"#( {
"address": "0x%x",
"name": "%s"
},)#",
&d,
d.name.c_str()
);
}
// remove trailing comma
if (result[result.size() - 1] == ',')
result.pop_back();
result += "\n],\n";
result += "\"switches\": [\n";
for (auto& d : g_pInputManager->m_lSwitches) {
result += getFormat(
R"#( { R"#( {
"address": "0x%x", "address": "0x%x",
"name": "%s" "name": "%s"
@@ -413,24 +448,24 @@ R"#( {
result += "mice:\n"; result += "mice:\n";
for (auto& m : g_pInputManager->m_lMice) { for (auto& m : g_pInputManager->m_lMice) {
result += getFormat("\tMouse at %x:\n\t\t%s\n\t\t\tdefault speed: %f\n", &m, m.mouse->name, (wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f)); result += getFormat("\tMouse at %x:\n\t\t%s\n\t\t\tdefault speed: %f\n", &m, m.name.c_str(), (wlr_input_device_is_libinput(m.mouse) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(m.mouse)) : 0.f));
} }
result += "\n\nKeyboards:\n"; result += "\n\nKeyboards:\n";
for (auto& k : g_pInputManager->m_lKeyboards) { for (auto& k : g_pInputManager->m_lKeyboards) {
const auto KM = g_pInputManager->getActiveLayoutForKeyboard(&k); const auto KM = g_pInputManager->getActiveLayoutForKeyboard(&k);
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n\t\t\tmain: %s\n", &k, k.keyboard->name, k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM.c_str(), (k.active ? "yes" : "no")); result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n\t\t\tmain: %s\n", &k, k.name.c_str(), k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM.c_str(), (k.active ? "yes" : "no"));
} }
result += "\n\nTablets:\n"; result += "\n\nTablets:\n";
for (auto& d : g_pInputManager->m_lTabletPads) { 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 += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->name.c_str() : "");
} }
for (auto& d : g_pInputManager->m_lTablets) { for (auto& d : g_pInputManager->m_lTablets) {
result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.wlrDevice ? d.wlrDevice->name : ""); result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.name.c_str());
} }
for (auto& d : g_pInputManager->m_lTabletTools) { for (auto& d : g_pInputManager->m_lTabletTools) {
@@ -440,7 +475,13 @@ R"#( {
result += "\n\nTouch:\n"; result += "\n\nTouch:\n";
for (auto& d : g_pInputManager->m_lTouchDevices) { for (auto& d : g_pInputManager->m_lTouchDevices) {
result += getFormat("\tTouch Device at %x:\n\t\t%s\n", &d, d.pWlrDevice ? d.pWlrDevice->name : ""); result += getFormat("\tTouch Device at %x:\n\t\t%s\n", &d, d.name.c_str());
}
result += "\n\nSwitches:\n";
for (auto& d : g_pInputManager->m_lSwitches) {
result += getFormat("\tSwitch Device at %x:\n\t\t%s\n", &d, d.pWlrDevice ? d.pWlrDevice->name : "");
} }
} }
@@ -471,7 +512,7 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
R"#({ R"#({
"branch": "%s", "branch": "%s",
"commit": "%s", "commit": "%s",
"dirty": %s "dirty": %s,
"commit_message": "%s", "commit_message": "%s",
"flags": [)#", GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE).c_str()); "flags": [)#", GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE).c_str());
@@ -533,12 +574,16 @@ std::string dispatchKeyword(std::string in) {
if (COMMAND.contains("input") || COMMAND.contains("device:")) { if (COMMAND.contains("input") || COMMAND.contains("device:")) {
g_pInputManager->setKeyboardLayout(); // update kb layout g_pInputManager->setKeyboardLayout(); // update kb layout
g_pInputManager->setMouseConfigs(); // update mouse cfgs g_pInputManager->setPointerConfigs(); // update mouse cfgs
g_pInputManager->setTouchDeviceConfigs(); // update touch device cfgs
} }
if (COMMAND.contains("general:layout")) if (COMMAND.contains("general:layout"))
g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout
if (COMMAND.contains("decoration:screen_shader"))
g_pHyprOpenGL->m_bReloadScreenShader = true;
Debug::log(LOG, "Hyprctl: keyword %s : %s", COMMAND.c_str(), VALUE.c_str()); Debug::log(LOG, "Hyprctl: keyword %s : %s", COMMAND.c_str(), VALUE.c_str());
if (retval == "") if (retval == "")
@@ -572,6 +617,23 @@ std::string splashRequest() {
return g_pCompositor->m_szCurrentSplash; return g_pCompositor->m_szCurrentSplash;
} }
std::string cursorPosRequest(HyprCtl::eHyprCtlOutputFormat format) {
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal().floor();
if (format == HyprCtl::FORMAT_NORMAL) {
return getFormat("%i, %i", (int)CURSORPOS.x, (int)CURSORPOS.y);
} else {
return getFormat(R"#(
{
"x": %i,
"y": %i
}
)#", (int)CURSORPOS.x, (int)CURSORPOS.y);
}
return "error";
}
std::string getReply(std::string); std::string getReply(std::string);
std::string dispatchBatch(std::string request) { std::string dispatchBatch(std::string request) {
@@ -656,6 +718,51 @@ std::string dispatchSetCursor(std::string request) {
return "ok"; return "ok";
} }
std::string switchXKBLayoutRequest(std::string request) {
CVarList vars(request, 0, ' ');
const auto KB = vars[1];
const auto CMD = vars[2];
// get kb
const auto PKEYBOARD = std::find_if(g_pInputManager->m_lKeyboards.begin(), g_pInputManager->m_lKeyboards.end(), [&] (const SKeyboard& other) { return other.name == g_pInputManager->deviceNameToInternalString(KB); });
if (PKEYBOARD == g_pInputManager->m_lKeyboards.end())
return "device not found";
const auto PWLRKEYBOARD = wlr_keyboard_from_input_device(PKEYBOARD->keyboard);
const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap);
xkb_layout_index_t activeLayout = 0;
while (activeLayout < LAYOUTS) {
if (xkb_state_layout_index_is_active(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE))
break;
activeLayout++;
}
if (CMD == "next") {
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1);
} else if (CMD == "prev") {
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
} else {
int requestedLayout = 0;
try {
requestedLayout = std::stoi(CMD);
} catch (std::exception& e) {
return "invalid arg 2";
}
if (requestedLayout < 0 || (uint64_t)requestedLayout > LAYOUTS - 1) {
return "layout idx out of range of " + std::to_string(LAYOUTS);
}
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, requestedLayout);
}
return "ok";
}
std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) { std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
std::string curitem = ""; std::string curitem = "";
@@ -682,21 +789,102 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
return "no such option"; return "no such option";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL)
return getFormat("option %s\n\tint: %i\n\tfloat: %f\n\tstr: \"%s\"", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str()); return getFormat("option %s\n\tint: %lld\n\tfloat: %f\n\tstr: \"%s\"\n\tdata: %x", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str(), PCFGOPT->data.get());
else { else {
return getFormat( return getFormat(
R"#( R"#(
{ {
"option": "%s", "option": "%s",
"int": %i, "int": %lld,
"float": %f, "float": %f,
"str": "%s" "str": "%s",
"data": "0x%x"
} }
)#", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str() )#", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str(), PCFGOPT->data.get()
); );
} }
} }
void createOutputIter(wlr_backend* backend, void* data) {
const auto DATA = (std::pair<std::string, bool>*)data;
if (DATA->second)
return;
if (DATA->first.empty() || DATA->first == "auto") {
if (wlr_backend_is_wl(backend)) {
wlr_wl_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_x11(backend)) {
wlr_x11_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_headless(backend)) {
wlr_headless_add_output(backend, 1920, 1080);
DATA->second = true;
}
} else {
if (wlr_backend_is_wl(backend) && DATA->first == "wayland") {
wlr_wl_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_x11(backend) && DATA->first == "x11") {
wlr_x11_output_create(backend);
DATA->second = true;
} else if (wlr_backend_is_headless(backend) && DATA->first == "headless") {
wlr_headless_add_output(backend, 1920, 1080);
DATA->second = true;
}
}
}
std::string dispatchOutput(std::string request) {
std::string curitem = "";
auto nextItem = [&]() {
auto idx = request.find_first_of(' ');
if (idx != std::string::npos) {
curitem = request.substr(0, idx);
request = request.substr(idx + 1);
} else {
curitem = request;
request = "";
}
curitem = removeBeginEndSpacesTabs(curitem);
};
nextItem();
nextItem();
const auto MODE = curitem;
nextItem();
const auto NAME = curitem;
if (MODE == "create" || MODE == "add") {
std::pair<std::string, bool> result = { NAME, false };
wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result);
if (!result.second)
return "no backend replied to the request";
} else if (MODE == "destroy" || MODE == "remove") {
const auto PMONITOR = g_pCompositor->getMonitorFromName(NAME);
if (!PMONITOR)
return "output not found";
if (!PMONITOR->createdByUser)
return "cannot remove a real display. Use the monitor keyword.";
wlr_output_destroy(PMONITOR->output);
}
return "ok";
}
std::string getReply(std::string request) { std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL; auto format = HyprCtl::FORMAT_NORMAL;
@@ -738,6 +926,12 @@ std::string getReply(std::string request) {
return devicesRequest(format); return devicesRequest(format);
else if (request == "splash") else if (request == "splash")
return splashRequest(); return splashRequest();
else if (request == "cursorpos")
return cursorPosRequest(format);
else if (request.find("switchxkblayout") == 0)
return switchXKBLayoutRequest(request);
else if (request.find("output") == 0)
return dispatchOutput(request);
else if (request.find("dispatch") == 0) else if (request.find("dispatch") == 0)
return dispatchRequest(request); return dispatchRequest(request);
else if (request.find("keyword") == 0) else if (request.find("keyword") == 0)

View File

@@ -6,6 +6,8 @@
#include "wlrunstable/wlr_ext_workspace_v1.hpp" #include "wlrunstable/wlr_ext_workspace_v1.hpp"
#include <utility>
#ifndef NDEBUG #ifndef NDEBUG
#ifdef HYPRLAND_DEBUG #ifdef HYPRLAND_DEBUG
#define ISDEBUG true #define ISDEBUG true
@@ -16,10 +18,10 @@
#define ISDEBUG false #define ISDEBUG false
#endif #endif
#define LISTENER(name) void listener_##name(wl_listener*, void*); inline wl_listener listen_##name = { .notify = listener_##name }; #define LISTENER(name) void listener_##name(wl_listener*, void*); inline wl_listener listen_##name = { .notify = listener_##name }
#define DYNLISTENFUNC(name) void listener_##name(void*, void*); #define DYNLISTENFUNC(name) void listener_##name(void*, void*)
#define DYNLISTENER(name) CHyprWLListener hyprListener_##name; #define DYNLISTENER(name) CHyprWLListener hyprListener_##name
#define DYNMULTILISTENER(name) wl_listener listen_##name; #define DYNMULTILISTENER(name) wl_listener listen_##name
#define VECINRECT(vec, x1, y1, x2, y2) (vec.x >= (x1) && vec.x <= (x2) && vec.y >= (y1) && vec.y <= (y2)) #define VECINRECT(vec, x1, y1, x2, y2) (vec.x >= (x1) && vec.x <= (x2) && vec.y >= (y1) && vec.y <= (y2))
@@ -29,6 +31,8 @@
const auto RECTSARR = pixman_region32_rectangles(region, &rectsNum); \ const auto RECTSARR = pixman_region32_rectangles(region, &rectsNum); \
for (int i = 0; i < rectsNum; ++i) for (int i = 0; i < rectsNum; ++i)
#define PIXMAN_REGION_FOREACH(region) PIXMAN_DAMAGE_FOREACH(region)
#define interface class #define interface class
@@ -74,4 +78,6 @@
#define GIT_DIRTY "?" #define GIT_DIRTY "?"
#endif #endif
#define SPECIAL_WORKSPACE_ID -99 #define SPECIAL_WORKSPACE_START -99
#define PI 3.14159265358979

View File

@@ -82,12 +82,16 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
Debug::log(LOG, "Attached a tablet pad with name %s", DEVICE->name); Debug::log(LOG, "Attached a tablet pad with name %s", DEVICE->name);
g_pInputManager->newTabletPad(DEVICE); g_pInputManager->newTabletPad(DEVICE);
break; break;
case WLR_INPUT_DEVICE_SWITCH:
Debug::log(LOG, "Attached a switch device with name %s", DEVICE->name);
g_pInputManager->newSwitch(DEVICE);
break;
default: default:
Debug::log(WARN, "Unrecognized input device plugged in: %s", DEVICE->name); Debug::log(WARN, "Unrecognized input device plugged in: %s", DEVICE->name);
break; break;
} }
g_pInputManager->updateCapabilities(DEVICE); g_pInputManager->updateCapabilities();
} }
void Events::listener_newConstraint(wl_listener* listener, void* data) { void Events::listener_newConstraint(wl_listener* listener, void* data) {
@@ -106,6 +110,11 @@ void Events::listener_newConstraint(wl_listener* listener, void* data) {
if (g_pCompositor->m_pLastFocus == PCONSTRAINT->surface) { if (g_pCompositor->m_pLastFocus == PCONSTRAINT->surface) {
g_pInputManager->constrainMouse(CONSTRAINT->pMouse, PCONSTRAINT); g_pInputManager->constrainMouse(CONSTRAINT->pMouse, PCONSTRAINT);
if (!CONSTRAINT->hintSet) {
const auto PWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
CONSTRAINT->positionHint = g_pInputManager->getMouseCoordsInternal() - PWINDOW->m_vRealPosition.goalv();
}
} }
} }
@@ -120,14 +129,14 @@ void Events::listener_destroyConstraint(void* owner, void* data) {
if (PWINDOW) { if (PWINDOW) {
if (PWINDOW->m_bIsX11) { if (PWINDOW->m_bIsX11) {
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr,
PCONSTRAINT->constraint->current.cursor_hint.x + PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y + PCONSTRAINT->constraint->current.cursor_hint.y); PCONSTRAINT->positionHint.x + PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y + PCONSTRAINT->positionHint.y);
wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->constraint->current.cursor_hint.x, PCONSTRAINT->constraint->current.cursor_hint.y); wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->positionHint.x, PCONSTRAINT->positionHint.y);
} else { } else {
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr,
PCONSTRAINT->constraint->current.cursor_hint.x + PWINDOW->m_vRealPosition.vec().x, PCONSTRAINT->constraint->current.cursor_hint.y + PWINDOW->m_vRealPosition.vec().y); PCONSTRAINT->positionHint.x + PWINDOW->m_vRealPosition.vec().x, PCONSTRAINT->positionHint.y + PWINDOW->m_vRealPosition.vec().y);
wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->constraint->current.cursor_hint.x, PCONSTRAINT->constraint->current.cursor_hint.y); wlr_seat_pointer_warp(PCONSTRAINT->constraint->seat, PCONSTRAINT->positionHint.x, PCONSTRAINT->positionHint.y);
} }
} }

View File

@@ -42,6 +42,7 @@ namespace Events {
// Surface XDG (window) // Surface XDG (window)
LISTENER(newXDGSurface); LISTENER(newXDGSurface);
LISTENER(activateXDG);
// Window events // Window events
DYNLISTENFUNC(commitWindow); DYNLISTENFUNC(commitWindow);
@@ -87,7 +88,6 @@ namespace Events {
LISTENER(requestMouse); LISTENER(requestMouse);
LISTENER(requestSetSel); LISTENER(requestSetSel);
LISTENER(requestSetPrimarySel); LISTENER(requestSetPrimarySel);
DYNLISTENFUNC(activate);
// outputMgr // outputMgr
LISTENER(outputMgrApply); LISTENER(outputMgrApply);
@@ -96,6 +96,7 @@ namespace Events {
// Monitor part 2 the sequel // Monitor part 2 the sequel
DYNLISTENFUNC(monitorFrame); DYNLISTENFUNC(monitorFrame);
DYNLISTENFUNC(monitorDestroy); DYNLISTENFUNC(monitorDestroy);
DYNLISTENFUNC(monitorStateRequest);
// XWayland // XWayland
LISTENER(readyXWayland); LISTENER(readyXWayland);

View File

@@ -31,15 +31,17 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
WLRLAYERSURFACE->output = PMONITOR->output; WLRLAYERSURFACE->output = PMONITOR->output;
} }
const auto PMONITOR = (CMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output); auto PMONITOR = (CMonitor*)g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output);
if (!WLRLAYERSURFACE->output || !PMONITOR || PMONITOR->pMirrorOf) {
PMONITOR = g_pCompositor->m_vMonitors.front().get();
WLRLAYERSURFACE->output = PMONITOR->output; // TODO: current mon
}
SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].emplace_back(std::make_unique<SLayerSurface>()).get(); SLayerSurface* layerSurface = PMONITOR->m_aLayerSurfaceLists[WLRLAYERSURFACE->pending.layer].emplace_back(std::make_unique<SLayerSurface>()).get();
layerSurface->szNamespace = WLRLAYERSURFACE->_namespace; layerSurface->szNamespace = WLRLAYERSURFACE->_namespace;
if (!WLRLAYERSURFACE->output) {
WLRLAYERSURFACE->output = g_pCompositor->m_vMonitors.front()->output; // TODO: current mon
}
layerSurface->hyprListener_commitLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.commit, &Events::listener_commitLayerSurface, layerSurface, "layerSurface"); layerSurface->hyprListener_commitLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.commit, &Events::listener_commitLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->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_mapLayerSurface.initCallback(&WLRLAYERSURFACE->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");
@@ -152,6 +154,8 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
layersurface->alpha = 255.f; layersurface->alpha = 255.f;
layersurface->readyToDelete = false; layersurface->readyToDelete = false;
layersurface->fadingOut = false; layersurface->fadingOut = false;
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
} }
void Events::listener_unmapLayerSurface(void* owner, void* data) { void Events::listener_unmapLayerSurface(void* owner, void* data) {
@@ -159,6 +163,8 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
Debug::log(LOG, "LayerSurface %x unmapped", layersurface->layerSurface); Debug::log(LOG, "LayerSurface %x unmapped", layersurface->layerSurface);
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) { if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
@@ -195,8 +201,29 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
// refocus if needed // refocus if needed
if (layersurface->layerSurface->surface == g_pCompositor->m_pLastFocus) { if (layersurface->layerSurface->surface == g_pCompositor->m_pLastFocus) {
Vector2D surfaceCoords;
SLayerSurface* pFoundLayerSurface = nullptr;
wlr_surface* foundSurface = nullptr;
g_pCompositor->m_pLastFocus = nullptr; g_pCompositor->m_pLastFocus = nullptr;
g_pInputManager->refocus();
// find LS-es to focus
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface);
if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface);
if (!foundSurface) {
// if there isn't any, focus the last window
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PLASTWINDOW);
} else {
// otherwise, full refocus
g_pInputManager->refocus();
}
} }
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height}; wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height};

View File

@@ -45,6 +45,7 @@ void Events::listener_requestSetSel(wl_listener* listener, void* data) {
} }
void Events::listener_readyXWayland(wl_listener* listener, void* data) { void Events::listener_readyXWayland(wl_listener* listener, void* data) {
#ifndef NO_XWAYLAND
const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL); const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL);
const auto ERR = xcb_connection_has_error(XCBCONNECTION); const auto ERR = xcb_connection_has_error(XCBCONNECTION);
if (ERR) { if (ERR) {
@@ -72,6 +73,7 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
} }
xcb_disconnect(XCBCONNECTION); xcb_disconnect(XCBCONNECTION);
#endif
} }
void Events::listener_requestDrag(wl_listener* listener, void* data) { void Events::listener_requestDrag(wl_listener* listener, void* data) {
@@ -124,6 +126,8 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
void Events::listener_destroyDrag(void* owner, void* data) { void Events::listener_destroyDrag(void* owner, void* data) {
Debug::log(LOG, "Drag destroyed."); Debug::log(LOG, "Drag destroyed.");
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
if (g_pInputManager->m_sDrag.drag && g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.dragIcon->surface) if (g_pInputManager->m_sDrag.drag && g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.dragIcon->surface)
g_pHyprRenderer->damageBox(g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4); g_pHyprRenderer->damageBox(g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4);
@@ -133,7 +137,7 @@ void Events::listener_destroyDrag(void* owner, void* data) {
g_pInputManager->refocus(); g_pInputManager->refocus();
if (g_pInputManager->m_pFollowOnDnDBegin) if (g_pInputManager->m_pFollowOnDnDBegin && *PFOLLOWMOUSE != 1)
g_pCompositor->focusWindow(g_pInputManager->m_pFollowOnDnDBegin); g_pCompositor->focusWindow(g_pInputManager->m_pFollowOnDnDBegin);
g_pInputManager->m_pFollowOnDnDBegin = nullptr; g_pInputManager->m_pFollowOnDnDBegin = nullptr;
@@ -187,6 +191,12 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
Debug::log(LOG, "Session got activated!"); Debug::log(LOG, "Session got activated!");
g_pCompositor->m_bSessionActive = true; g_pCompositor->m_bSessionActive = true;
for (auto& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m.get());
}
g_pConfigManager->m_bWantsMonitorReload = true;
} }
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) { void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {

View File

@@ -37,8 +37,6 @@ void Events::listener_change(wl_listener* listener, void* data) {
CONFIGHEAD->state.mode = m->output->current_mode; CONFIGHEAD->state.mode = m->output->current_mode;
CONFIGHEAD->state.x = m->vecPosition.x; CONFIGHEAD->state.x = m->vecPosition.x;
CONFIGHEAD->state.y = m->vecPosition.y; CONFIGHEAD->state.y = m->vecPosition.y;
wlr_output_set_custom_mode(m->output, m->vecPixelSize.x, m->vecPixelSize.y, (int)(round(m->refreshRate * 1000)));
} }
wlr_output_manager_v1_set_configuration(g_pCompositor->m_sWLROutputMgr, CONFIG); wlr_output_manager_v1_set_configuration(g_pCompositor->m_sWLROutputMgr, CONFIG);
@@ -90,6 +88,9 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
g_pCompositor->m_bReadyToProcess = true; g_pCompositor->m_bReadyToProcess = true;
g_pCompositor->m_bUnsafeState = false; g_pCompositor->m_bUnsafeState = false;
} }
g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
} }
void Events::listener_monitorFrame(void* owner, void* data) { void Events::listener_monitorFrame(void* owner, void* data) {
@@ -108,9 +109,10 @@ void Events::listener_monitorFrame(void* owner, void* data) {
static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
static auto *const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue; static auto *const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
static auto *const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("general:damage_tracking_internal")->intValue; static auto *const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("debug:damage_tracking")->intValue;
static auto *const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue; static auto *const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue;
static auto *const PNOVFR = &g_pConfigManager->getConfigValuePtr("misc:no_vfr")->intValue; static auto *const PNOVFR = &g_pConfigManager->getConfigValuePtr("misc:no_vfr")->intValue;
static auto *const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue;
static int damageBlinkCleanup = 0; // because double-buffered static int damageBlinkCleanup = 0; // because double-buffered
@@ -156,6 +158,16 @@ void Events::listener_monitorFrame(void* owner, void* data) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
} }
// Direct scanout first
if (!*PNODIRECTSCANOUT) {
if (g_pHyprRenderer->attemptDirectScanout(PMONITOR)) {
return;
} else if (g_pHyprRenderer->m_pLastScanout) {
Debug::log(LOG, "Left a direct scanout.");
g_pHyprRenderer->m_pLastScanout = nullptr;
}
}
timespec now; timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
@@ -227,8 +239,6 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (PMONITOR->isMirror()) { if (PMONITOR->isMirror()) {
g_pHyprOpenGL->renderMirrored(); g_pHyprOpenGL->renderMirrored();
Debug::log(LOG, "Mirror frame");
} else { } else {
g_pHyprOpenGL->clear(CColor(17, 17, 17, 255)); g_pHyprOpenGL->clear(CColor(17, 17, 17, 255));
g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
@@ -236,11 +246,11 @@ void Events::listener_monitorFrame(void* owner, void* data) {
g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now); g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now);
// if correct monitor draw hyprerror // if correct monitor draw hyprerror
if (PMONITOR->ID == 0) if (PMONITOR == g_pCompositor->m_vMonitors.front().get())
g_pHyprError->draw(); g_pHyprError->draw();
// for drawing the debug overlay // for drawing the debug overlay
if (PMONITOR->ID == 0 && *PDEBUGOVERLAY == 1) { if (PMONITOR == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) {
startRenderOverlay = std::chrono::high_resolution_clock::now(); startRenderOverlay = std::chrono::high_resolution_clock::now();
g_pDebugOverlay->draw(); g_pDebugOverlay->draw();
endRenderOverlay = std::chrono::high_resolution_clock::now(); endRenderOverlay = std::chrono::high_resolution_clock::now();
@@ -256,15 +266,16 @@ void Events::listener_monitorFrame(void* owner, void* data) {
damageBlinkCleanup = 0; damageBlinkCleanup = 0;
} }
wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); if (wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y)) {
wlr_output_render_software_cursors(PMONITOR->output, NULL);
wlr_output_render_software_cursors(PMONITOR->output, NULL); wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
}
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
} }
g_pHyprOpenGL->end(); g_pHyprOpenGL->end();
g_pProtocolManager->m_pToplevelExportProtocolManager->onMonitorRender(PMONITOR); // dispatch any toplevel sharing
// calc frame damage // calc frame damage
pixman_region32_t frameDamage; pixman_region32_t frameDamage;
pixman_region32_init(&frameDamage); pixman_region32_init(&frameDamage);
@@ -295,7 +306,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (*PDEBUGOVERLAY == 1) { if (*PDEBUGOVERLAY == 1) {
const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f; const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
g_pDebugOverlay->renderData(PMONITOR, µs); g_pDebugOverlay->renderData(PMONITOR, µs);
if (PMONITOR->ID == 0) { if (PMONITOR == g_pCompositor->m_vMonitors.front().get()) {
const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f; const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f;
g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µsNoOverlay); g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µsNoOverlay);
} else { } else {
@@ -309,8 +320,8 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
CMonitor* pMonitor = nullptr; CMonitor* pMonitor = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->szName == OUTPUT->name) { if (m->output == OUTPUT) {
pMonitor = m.get(); pMonitor = m.get();
break; break;
} }
@@ -319,11 +330,14 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
if (!pMonitor) if (!pMonitor)
return; return;
Debug::log(LOG, "Destroy called for monitor %s", pMonitor->output->name);
pMonitor->onDisconnect(); pMonitor->onDisconnect();
// cleanup if not unsafe // cleanup if not unsafe
if (!g_pCompositor->m_bUnsafeState) { if (!g_pCompositor->m_bUnsafeState) {
Debug::log(LOG, "Removing monitor %s from realMonitors", pMonitor->output->name);
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; })); g_pCompositor->m_vRealMonitors.erase(std::remove_if(g_pCompositor->m_vRealMonitors.begin(), g_pCompositor->m_vRealMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; }));
if (pMostHzMonitor == pMonitor) { if (pMostHzMonitor == pMonitor) {
@@ -341,3 +355,10 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
} }
} }
} }
void Events::listener_monitorStateRequest(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_request_state*)data;
wlr_output_commit_state(PMONITOR->output, E->state);
}

View File

@@ -32,8 +32,8 @@ void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
py -= curPopup->popup->base->current.geometry.y; py -= curPopup->popup->base->current.geometry.y;
} }
if (curPopup->pSurfaceTree && curPopup->pSurfaceTree->pSurface && !curPopup->parentPopup && !curPopup->parentWindow) { if (curPopup->popup && !curPopup->parentPopup && !curPopup->parentWindow) {
const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->pSurfaceTree->pSurface->input_region); const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->popup->base->surface->input_region);
px -= EXTENTSSURFACE->x1; px -= EXTENTSSURFACE->x1;
py -= EXTENTSSURFACE->y1; py -= EXTENTSSURFACE->y1;
} }

View File

@@ -20,7 +20,7 @@ void addViewCoords(void* pWindow, int* x, int* y) {
*x += PWINDOW->m_vRealPosition.goalv().x; *x += PWINDOW->m_vRealPosition.goalv().x;
*y += PWINDOW->m_vRealPosition.goalv().y; *y += PWINDOW->m_vRealPosition.goalv().y;
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) {
wlr_box geom; wlr_box geom;
wlr_xdg_surface_get_geometry(PWINDOW->m_uSurface.xdg, &geom); wlr_xdg_surface_get_geometry(PWINDOW->m_uSurface.xdg, &geom);
@@ -29,18 +29,12 @@ void addViewCoords(void* pWindow, int* x, int* y) {
} }
} }
int setAnimToMove(void* data) { void setAnimToMove(void* data) {
const auto PWINDOW = (CWindow*)data;
auto *const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove"); auto *const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
if (!g_pCompositor->windowValidMapped(PWINDOW)) CAnimatedVariable* animvar = (CAnimatedVariable*)data;
return 0;
PWINDOW->m_vRealPosition.setConfig(PANIMCFG); animvar->setConfig(PANIMCFG);
PWINDOW->m_vRealSize.setConfig(PANIMCFG);
return 0;
} }
void Events::listener_mapWindow(void* owner, void* data) { void Events::listener_mapWindow(void* owner, void* data) {
@@ -52,11 +46,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
static auto *const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue; static auto *const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
static auto *const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue; static auto *const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
const auto PMONITOR = g_pCompositor->m_pLastMonitor; auto PMONITOR = g_pCompositor->m_pLastMonitor;
const auto PWORKSPACE = PMONITOR->specialWorkspaceOpen ? g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto PWORKSPACE = PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_iMonitorID = PMONITOR->ID;
PWINDOW->m_bMappedX11 = true; PWINDOW->m_bMappedX11 = true;
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceOpen ? SPECIAL_WORKSPACE_ID : PMONITOR->activeWorkspace; PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
PWINDOW->m_bIsMapped = true; PWINDOW->m_bIsMapped = true;
PWINDOW->m_bReadyToDelete = false; PWINDOW->m_bReadyToDelete = false;
PWINDOW->m_bFadingOut = false; PWINDOW->m_bFadingOut = false;
@@ -65,8 +59,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PWINDOW->m_iX11Type == 2) if (PWINDOW->m_iX11Type == 2)
g_pCompositor->moveUnmanagedX11ToWindows(PWINDOW); g_pCompositor->moveUnmanagedX11ToWindows(PWINDOW);
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
// Set all windows tiled regardless of anything // Set all windows tiled regardless of anything
g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM); g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
@@ -76,6 +68,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
// checks if the window wants borders and sets the appriopriate flag // checks if the window wants borders and sets the appriopriate flag
g_pXWaylandManager->checkBorders(PWINDOW); g_pXWaylandManager->checkBorders(PWINDOW);
// registers the animated vars and stuff
PWINDOW->onMap();
const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(PWINDOW); const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(PWINDOW);
if (!PWINDOWSURFACE) { if (!PWINDOWSURFACE) {
@@ -112,8 +107,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW); const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
std::string requestedWorkspace = ""; std::string requestedWorkspace = "";
bool workspaceSilent = false; bool workspaceSilent = false;
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen); bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen) || (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen);
bool shouldFocus = true; bool shouldFocus = true;
bool workspaceSpecial = false;
for (auto& r : WINDOWRULES) { for (auto& r : WINDOWRULES) {
if (r.szRule.find("monitor") == 0) { if (r.szRule.find("monitor") == 0) {
@@ -131,7 +127,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace; PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID)); if (PWINDOW->m_iMonitorID != PMONITOR->ID) {
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
}
Debug::log(ERR, "Rule monitor, applying to window %x -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID); Debug::log(ERR, "Rule monitor, applying to window %x -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID);
} catch (std::exception& e) { } catch (std::exception& e) {
@@ -147,6 +146,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
requestedWorkspace = WORKSPACERQ; requestedWorkspace = WORKSPACERQ;
} }
if (requestedWorkspace == PWORKSPACE->m_szName || requestedWorkspace == "name:" + PWORKSPACE->m_szName)
requestedWorkspace = "";
Debug::log(LOG, "Rule workspace matched by window %x, %s applied.", PWINDOW, r.szValue.c_str()); Debug::log(LOG, "Rule workspace matched by window %x, %s applied.", PWINDOW, r.szValue.c_str());
} else if (r.szRule.find("float") == 0) { } else if (r.szRule.find("float") == 0) {
PWINDOW->m_bIsFloating = true; PWINDOW->m_bIsFloating = true;
@@ -156,40 +158,34 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bIsPseudotiled = true; PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.find("nofocus") == 0) { } else if (r.szRule.find("nofocus") == 0) {
PWINDOW->m_bNoFocus = true; PWINDOW->m_bNoFocus = true;
} else if (r.szRule == "noblur") { } else if (r.szRule.find("nofullscreenrequest") == 0) {
PWINDOW->m_sAdditionalConfigData.forceNoBlur = true; PWINDOW->m_bNoFullscreenRequest = true;
} else if (r.szRule == "fullscreen") { } else if (r.szRule == "fullscreen") {
requestsFullscreen = true; requestsFullscreen = true;
} else if (r.szRule == "opaque") { } else if (r.szRule == "windowdance") {
PWINDOW->m_sAdditionalConfigData.forceOpaque = true; PWINDOW->m_sAdditionalConfigData.windowDanceCompat = true;
} else if (r.szRule == "nomaxsize") {
PWINDOW->m_sAdditionalConfigData.noMaxSize = true;
} else if (r.szRule == "forceinput") { } else if (r.szRule == "forceinput") {
PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true; PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true;
} else if (r.szRule == "pin") { } else if (r.szRule == "pin") {
PWINDOW->m_bPinned = true; PWINDOW->m_bPinned = true;
} else if (r.szRule.find("rounding") == 0) { } else if (r.szRule.find("idleinhibit") == 0) {
try { auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
PWINDOW->m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) {
Debug::log(ERR, "Rounding rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
}
} else if (r.szRule.find("opacity") == 0) {
try {
std::string alphaPart = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (alphaPart.contains(' ')) { if (IDLERULE == "none") {
// we have a comma, 2 values PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_NONE;
PWINDOW->m_sSpecialRenderData.alpha = std::stof(alphaPart.substr(0, alphaPart.find_first_of(' '))); } else if (IDLERULE == "always") {
PWINDOW->m_sSpecialRenderData.alphaInactive = std::stof(alphaPart.substr(alphaPart.find_first_of(' ') + 1)); PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
} else { } else if (IDLERULE == "focus") {
PWINDOW->m_sSpecialRenderData.alpha = std::stof(alphaPart); PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
} } else if (IDLERULE == "fullscreen") {
} catch(std::exception& e) { PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what()); } else {
Debug::log(ERR, "Rule idleinhibit: unknown mode %s", IDLERULE.c_str());
} }
} else if (r.szRule.find("animation") == 0) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
PWINDOW->m_sAdditionalConfigData.animationStyle = STYLE;
} }
PWINDOW->applyDynamicRule(r);
} }
// disallow tiled pinned // disallow tiled pinned
@@ -203,16 +199,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (requestedWorkspace.contains("silent")) { if (requestedWorkspace.contains("silent")) {
workspaceSilent = true; workspaceSilent = true;
shouldFocus = false; shouldFocus = false;
}
requestedWorkspace = requestedWorkspace.substr(0, requestedWorkspace.find_first_of(' ')); requestedWorkspace = requestedWorkspace.substr(0, requestedWorkspace.find_first_of(' '));
}
if (!shouldFocus && requestedWorkspace == std::to_string(PMONITOR->activeWorkspace)) if (!shouldFocus && requestedWorkspace == std::to_string(PMONITOR->activeWorkspace))
shouldFocus = true; shouldFocus = true;
}
if (requestedWorkspace == "special") { if (requestedWorkspace.find("special" == 0)) {
workspaceSilent = true; workspaceSpecial = true;
}
} }
if (!workspaceSilent) { if (!workspaceSilent) {
@@ -220,6 +216,46 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID; PWINDOW->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID;
PWINDOW->m_iWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace; PWINDOW->m_iWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
PMONITOR = g_pCompositor->m_pLastMonitor;
}
}
if (workspaceSilent) {
// get the workspace
auto PWORKSPACE = g_pCompositor->getWorkspaceByString(requestedWorkspace);
if (!PWORKSPACE) {
std::string workspaceName = "";
int workspaceID = 0;
if (requestedWorkspace.find("name:") == 0) {
workspaceName = requestedWorkspace.substr(5);
workspaceID = g_pCompositor->getNextAvailableNamedWorkspace();
} else if (workspaceSpecial) {
workspaceName = "";
workspaceID = getWorkspaceIDFromString(requestedWorkspace, workspaceName);
} else {
try {
workspaceID = std::stoi(requestedWorkspace);
} catch (...) {
workspaceID = -1;
Debug::log(ERR, "Invalid workspace requested in workspace silent rule!");
}
if (workspaceID < 1) {
workspaceID = -1; // means invalid
}
}
if (workspaceID != -1)
PWORKSPACE = g_pCompositor->createNewWorkspace(workspaceID, PWINDOW->m_iMonitorID, workspaceName);
}
if (PWORKSPACE) {
PWINDOW->m_iWorkspaceID = PWORKSPACE->m_iID;
PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID;
} }
} }
@@ -245,24 +281,96 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY); PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
PWINDOW->m_bHidden = false; PWINDOW->setHidden(false);
} catch (...) { } catch (...) {
Debug::log(LOG, "Rule size failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str()); Debug::log(LOG, "Rule size failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
} }
} else if (r.szRule.find("move") == 0) { } else if (r.szRule.find("minsize") == 0) {
try { try {
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1); const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
const auto POSXSTR = VALUE.substr(0, VALUE.find(" ")); const auto SIZEXSTR = VALUE.substr(0, VALUE.find(" "));
const auto POSYSTR = VALUE.substr(VALUE.find(" ") + 1); const auto SIZEYSTR = VALUE.substr(VALUE.find(" ") + 1);
const auto POSX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x; const auto SIZE = Vector2D(std::max((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::max((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goalv().y));
const auto POSY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
PWINDOW->m_vRealSize = SIZE;
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
PWINDOW->setHidden(false);
} catch (...) {
Debug::log(LOG, "Rule minsize failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
}
} else if (r.szRule.find("maxsize") == 0) {
try {
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(" "));
const auto SIZEYSTR = VALUE.substr(VALUE.find(" ") + 1);
const auto SIZE = Vector2D(std::min((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::min((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goalv().y));
PWINDOW->m_vRealSize = SIZE;
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
PWINDOW->setHidden(false);
} catch (...) {
Debug::log(LOG, "Rule maxsize failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
}
} else if (r.szRule.find("move") == 0) {
try {
auto value = r.szRule.substr(r.szRule.find(" ") + 1);
const bool CURSOR = value.find("cursor") == 0;
if (CURSOR)
value = value.substr(value.find_first_of(' ') + 1);
const auto POSXSTR = value.substr(0, value.find(" "));
const auto POSYSTR = value.substr(value.find(" ") + 1);
int posX = 0;
int posY = 0;
if (POSXSTR.find("100%-") == 0) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto POSXRAW = POSXSTR.substr(5);
posX = PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stoi(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
} else {
// cursor
if (POSXSTR == "cursor") {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
} else {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x + (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().x);
}
}
if (POSYSTR.find("100%-") == 0) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto POSYRAW = POSYSTR.substr(5);
posY = PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stoi(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
} else {
// cursor
if (POSYSTR == "cursor") {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
} else {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y + (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().y);
}
}
Debug::log(LOG, "Rule move, applying to window %x", PWINDOW); Debug::log(LOG, "Rule move, applying to window %x", PWINDOW);
PWINDOW->m_vRealPosition = Vector2D(POSX, POSY) + PMONITOR->vecPosition; PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
PWINDOW->m_bHidden = false; PWINDOW->setHidden(false);
} catch (...) { } catch (...) {
Debug::log(LOG, "Rule move failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str()); Debug::log(LOG, "Rule move failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
} }
@@ -276,8 +384,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv(); PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv();
g_pCompositor->moveWindowToTop(PWINDOW); g_pCompositor->moveWindowToTop(PWINDOW);
} } else {
else {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
// Set the pseudo size here too so that it doesnt end up being 0x0 // Set the pseudo size here too so that it doesnt end up being 0x0
@@ -292,7 +399,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bX11ShouldntFocus = false; PWINDOW->m_bX11ShouldntFocus = false;
} }
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus && PWINDOW->m_iX11Type != 2) { // check LS focus grab
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
PWINDOW->m_bNoInitialFocus = true;
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus && PWINDOW->m_iX11Type != 2 && !workspaceSilent) {
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(*PDIMSTRENGTH); PWINDOW->m_fDimPercent.setValueAndWarp(*PDIMSTRENGTH);
@@ -317,6 +429,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW, "XWayland Window Late");
PWINDOW->hyprListener_configureX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_configure, &Events::listener_configureX11, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_configureX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_configure, &Events::listener_configureX11, PWINDOW, "XWayland Window Late");
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XWayland Window Late");
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_minimize, &Events::listener_requestMinimize, PWINDOW, "Xwayland Window Late");
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_maximize, &Events::listener_requestMaximize, PWINDOW, "Xwayland Window Late");
if (PWINDOW->m_iX11Type == 2) if (PWINDOW->m_iX11Type == 2)
PWINDOW->hyprListener_setGeometryX11U.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_geometry, &Events::listener_unmanagedSetGeometry, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_setGeometryX11U.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_geometry, &Events::listener_unmanagedSetGeometry, PWINDOW, "XWayland Window Late");
@@ -327,26 +441,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_fAlpha.setValueAndWarp(0.f); PWINDOW->m_fAlpha.setValueAndWarp(0.f);
PWINDOW->m_fAlpha = 255.f; PWINDOW->m_fAlpha = 255.f;
const auto TIMER = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, setAnimToMove, PWINDOW); PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove);
wl_event_source_timer_update(TIMER, PWINDOW->m_vRealPosition.getDurationLeftMs() + 5); PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove);
if (workspaceSilent) { if (requestsFullscreen && !PWINDOW->m_bNoFullscreenRequest) {
// move the window
const auto OLDWORKSPACE = PWINDOW->m_iWorkspaceID;
if (g_pCompositor->m_pLastWindow == PWINDOW) {
if (requestedWorkspace != "special")
g_pKeybindManager->m_mDispatchers["movetoworkspacesilent"](requestedWorkspace);
else
g_pKeybindManager->m_mDispatchers["movetoworkspace"]("special");
} else {
Debug::log(ERR, "Tried to set workspace silent rule to a nofocus window!");
}
g_pCompositor->forceReportSizesToWindowsOnWorkspace(OLDWORKSPACE);
}
if (requestsFullscreen) {
// fix fullscreen on requested (basically do a switcheroo) // fix fullscreen on requested (basically do a switcheroo)
if (PWORKSPACE->m_bHasFullscreenWindow) { if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
@@ -380,39 +478,59 @@ void Events::listener_mapWindow(void* owner, void* data) {
// verify swallowing // verify swallowing
if (*PSWALLOW) { if (*PSWALLOW) {
// check parent // don't swallow ourselves
int ppid = getPPIDof(PWINDOW->getPID()); std::regex rgx(*PSWALLOWREGEX);
if (!std::regex_match(g_pXWaylandManager->getAppIDClass(PWINDOW), rgx)) {
// check parent
int ppid = getPPIDof(PWINDOW->getPID());
const auto PPPID = getPPIDof(ppid); int curppid = 0;
// why? no clue. Blame terminals. for (int i = 0; i < 5; ++i) {
if (PPPID > 2) { curppid = getPPIDof(ppid);
ppid = PPPID;
}
if (ppid) { if (curppid < 10) {
// get window by pid
CWindow* found = nullptr;
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_bHidden)
continue;
if (w->getPID() == ppid) {
found = w.get();
break; break;
} }
ppid = curppid;
} }
if (found) { if (ppid) {
// check if it's the window we want // get window by pid
std::regex rgx(*PSWALLOWREGEX); std::vector<CWindow*> found;
if (std::regex_match(g_pXWaylandManager->getAppIDClass(found), rgx)) { CWindow* finalFound = nullptr;
// swallow for (auto& w : g_pCompositor->m_vWindows) {
PWINDOW->m_pSwallowed = found; if (!w->m_bIsMapped || w->isHidden())
continue;
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(found); if (w->getPID() == ppid) {
found.push_back(w.get());
}
}
found->m_bHidden = true; if (found.size() > 1) {
for (auto& w : found) {
// try get the focus, otherwise we'll ignore to avoid swallowing incorrect windows
if (w == PFOCUSEDWINDOWPREV) {
finalFound = w;
break;
}
}
} else if (found.size() == 1) {
finalFound = found[0];
}
if (finalFound) {
// check if it's the window we want
if (std::regex_match(g_pXWaylandManager->getAppIDClass(finalFound), rgx)) {
// swallow
PWINDOW->m_pSwallowed = finalFound;
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(finalFound);
finalFound->setHidden(true);
}
} }
} }
} }
@@ -422,6 +540,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName; auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", getFormat("%x,%s,%s,%s", PWINDOW, workspaceID.c_str(), g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), PWINDOW->m_szTitle.c_str())}); g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", getFormat("%x,%s,%s,%s", PWINDOW, workspaceID.c_str(), g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), PWINDOW->m_szTitle.c_str())});
// recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
} }
void Events::listener_unmapWindow(void* owner, void* data) { void Events::listener_unmapWindow(void* owner, void* data) {
@@ -431,6 +552,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%x", PWINDOW)}); g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%x", PWINDOW)});
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW);
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
Debug::log(LOG, "Unregistered late callbacks XDG"); Debug::log(LOG, "Unregistered late callbacks XDG");
PWINDOW->hyprListener_commitWindow.removeCallback(); PWINDOW->hyprListener_commitWindow.removeCallback();
@@ -448,6 +571,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->hyprListener_configureX11.removeCallback(); PWINDOW->hyprListener_configureX11.removeCallback();
PWINDOW->hyprListener_setTitleWindow.removeCallback(); PWINDOW->hyprListener_setTitleWindow.removeCallback();
PWINDOW->hyprListener_setGeometryX11U.removeCallback(); PWINDOW->hyprListener_setGeometryX11U.removeCallback();
PWINDOW->hyprListener_requestMaximize.removeCallback();
PWINDOW->hyprListener_requestMinimize.removeCallback();
} }
if (PWINDOW->m_bIsFullscreen) { if (PWINDOW->m_bIsFullscreen) {
@@ -459,7 +584,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
// swallowing // swallowing
if (PWINDOW->m_pSwallowed && g_pCompositor->windowExists(PWINDOW->m_pSwallowed)) { if (PWINDOW->m_pSwallowed && g_pCompositor->windowExists(PWINDOW->m_pSwallowed)) {
PWINDOW->m_pSwallowed->m_bHidden = false; PWINDOW->m_pSwallowed->setHidden(false);
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed);
PWINDOW->m_pSwallowed = nullptr; PWINDOW->m_pSwallowed = nullptr;
} }
@@ -487,13 +612,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
// refocus on a new window if needed // refocus on a new window if needed
if (wasLastWindow) { if (wasLastWindow) {
auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f); const auto PWINDOWCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW);
if (PWORKSPACE->m_bHasFullscreenWindow && ((!PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bCreatedOverFullscreen) || !PWINDOW->m_bIsFloating))
PWINDOWCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
if (!PWINDOWCANDIDATE || PWINDOW == PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bIsMapped || PWINDOWCANDIDATE->m_bHidden || PWINDOWCANDIDATE->m_bX11ShouldntFocus || PWINDOWCANDIDATE->m_iX11Type == 2 || PWINDOWCANDIDATE->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
PWINDOWCANDIDATE = nullptr;
Debug::log(LOG, "On closed window, new focused candidate is %x", PWINDOWCANDIDATE); Debug::log(LOG, "On closed window, new focused candidate is %x", PWINDOWCANDIDATE);
@@ -502,6 +621,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pInputManager->refocus(); g_pInputManager->refocus();
else else
g_pCompositor->focusWindow(PWINDOWCANDIDATE); g_pCompositor->focusWindow(PWINDOWCANDIDATE);
} else {
g_pInputManager->refocus();
} }
} else { } else {
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus."); Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
@@ -536,12 +657,18 @@ void Events::listener_unmapWindow(void* owner, void* data) {
// recheck idle inhibitors // recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
// force report all sizes (QT sometimes has an issue with this)
g_pCompositor->forceReportSizesToWindowsOnWorkspace(PWINDOW->m_iWorkspaceID);
// update lastwindow after focus
PWINDOW->onUnmap();
} }
void Events::listener_commitWindow(void* owner, void* data) { void Events::listener_commitWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_bHidden || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11)) if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11))
return; return;
g_pHyprRenderer->damageSurface(g_pXWaylandManager->getWindowSurface(PWINDOW), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y); g_pHyprRenderer->damageSurface(g_pXWaylandManager->getWindowSurface(PWINDOW), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y);
@@ -575,6 +702,11 @@ void Events::listener_destroyWindow(void* owner, void* data) {
} }
PWINDOW->m_bReadyToDelete = true; PWINDOW->m_bReadyToDelete = true;
if (!PWINDOW->m_bFadingOut) {
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
Debug::log(LOG, "Unmapped window %x removed instantly", PWINDOW);
}
} }
void Events::listener_setTitleWindow(void* owner, void* data) { void Events::listener_setTitleWindow(void* owner, void* data) {
@@ -588,6 +720,8 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
if (PWINDOW == g_pCompositor->m_pLastWindow) // if it's the active, let's post an event to update others if (PWINDOW == g_pCompositor->m_pLastWindow) // if it's the active, let's post an event to update others
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle});
PWINDOW->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
PWINDOW->updateToplevel(); PWINDOW->updateToplevel();
Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str()); Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str());
@@ -601,7 +735,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
return; return;
} }
if (PWINDOW->m_bHidden) if (PWINDOW->isHidden() || PWINDOW->m_bNoFullscreenRequest)
return; return;
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
@@ -612,26 +746,50 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg); wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
} else { } else {
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_FULL); if (!PWINDOW->m_uSurface.xwayland->mapped)
return;
g_pCompositor->setWindowFullscreen(PWINDOW, PWINDOW->m_uSurface.xwayland->fullscreen, FULLSCREEN_FULL);
} }
PWINDOW->updateToplevel(); PWINDOW->updateToplevel();
Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen); Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen);
g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen);
} }
void Events::listener_activate(void* owner, void* data) { void Events::listener_activateXDG(wl_listener* listener, void* data) {
// TODO const auto E = (wlr_xdg_activation_v1_request_activate_event*)data;
static auto *const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
Debug::log(LOG, "Activate request for surface at %x", E->surface);
if (!*PFOCUSONACTIVATE || !wlr_surface_is_xdg_surface(E->surface))
return;
const auto PWINDOW = g_pCompositor->getWindowFromSurface(E->surface);
if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow)
return;
g_pCompositor->focusWindow(PWINDOW);
Vector2D middle = PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f;
g_pCompositor->warpCursorTo(middle);
} }
void Events::listener_activateX11(void* owner, void* data) { void Events::listener_activateX11(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; const auto PWINDOW = (CWindow*)owner;
if (PWINDOW->m_iX11Type == 1 /* Managed */) { static auto *const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
wlr_xwayland_surface_activate(PWINDOW->m_uSurface.xwayland, 1);
} Debug::log(LOG, "X11 Activate request for window %x", PWINDOW);
if (!*PFOCUSONACTIVATE || PWINDOW->m_iX11Type != 1 || PWINDOW == g_pCompositor->m_pLastWindow)
return;
g_pCompositor->focusWindow(PWINDOW);
Vector2D middle = PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f;
g_pCompositor->warpCursorTo(middle);
} }
void Events::listener_configureX11(void* owner, void* data) { void Events::listener_configureX11(void* owner, void* data) {
@@ -644,21 +802,21 @@ void Events::listener_configureX11(void* owner, void* data) {
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) { if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec()); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
return; return;
} }
if (!PWINDOW->m_uSurface.xwayland->mapped) { if (!PWINDOW->m_uSurface.xwayland->mapped || !PWINDOW->m_bMappedX11) {
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height); wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
return; return;
} }
if (E->width > 1 && E->height > 1) if (E->width > 1 && E->height > 1)
PWINDOW->m_bHidden = false; PWINDOW->setHidden(false);
else else
PWINDOW->m_bHidden = true; PWINDOW->setHidden(true);
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(E->x, E->y)); PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(E->x, E->y));
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height)); PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height));
@@ -673,7 +831,8 @@ void Events::listener_configureX11(void* owner, void* data) {
PWINDOW->m_bCreatedOverFullscreen = true; PWINDOW->m_bCreatedOverFullscreen = true;
g_pInputManager->refocus(); if (!PWINDOW->m_sAdditionalConfigData.windowDanceCompat)
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
@@ -683,16 +842,22 @@ void Events::listener_configureX11(void* owner, void* data) {
void Events::listener_unmanagedSetGeometry(void* owner, void* data) { void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_bHidden) if (!PWINDOW->m_bMappedX11)
return; return;
const auto POS = PWINDOW->m_vRealPosition.goalv(); const auto POS = PWINDOW->m_vRealPosition.goalv();
const auto SIZ = PWINDOW->m_vRealSize.goalv(); const auto SIZ = PWINDOW->m_vRealSize.goalv();
if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1) if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1)
PWINDOW->m_bHidden = false; PWINDOW->setHidden(false);
else else
PWINDOW->m_bHidden = true; PWINDOW->setHidden(true);
if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
g_pHyprRenderer->damageWindow(PWINDOW);
return;
}
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) { 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); 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);
@@ -756,15 +921,37 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
void Events::listener_requestMaximize(void* owner, void* data) { void Events::listener_requestMaximize(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner; const auto PWINDOW = (CWindow*)owner;
const auto EV = (wlr_foreign_toplevel_handle_v1_maximized_event*)data; if (PWINDOW->m_bNoFullscreenRequest)
return;
g_pCompositor->setWindowFullscreen(PWINDOW, EV ? EV->maximized : !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED); // this will be rejected if there already is a fullscreen window Debug::log(LOG, "Maximize request for %x", PWINDOW);
if (!PWINDOW->m_bIsX11) {
const auto EV = (wlr_foreign_toplevel_handle_v1_maximized_event*)data;
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg); g_pCompositor->setWindowFullscreen(PWINDOW, EV ? EV->maximized : !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED); // this will be rejected if there already is a fullscreen window
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
} else {
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
return;
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED);
}
} }
void Events::listener_requestMinimize(void* owner, void* data) { void Events::listener_requestMinimize(void* owner, void* data) {
// ignore const auto PWINDOW = (CWindow*)owner;
Debug::log(LOG, "Minimize request for %x", PWINDOW);
if (PWINDOW->m_bIsX11) {
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
return;
const auto E = (wlr_xwayland_minimize_event*)data;
wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow != PWINDOW); // fucking DXVK
}
} }
void Events::listener_requestMove(void* owner, void* data) { void Events::listener_requestMove(void* owner, void* data) {

View File

@@ -12,8 +12,6 @@ void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* p
m_pConfig = pAnimConfig; m_pConfig = pAnimConfig;
m_pWindow = pWindow; m_pWindow = pWindow;
g_pAnimationManager->m_lAnimatedVariables.push_back(this);
m_bDummy = false; m_bDummy = false;
} }
@@ -56,8 +54,20 @@ CAnimatedVariable::~CAnimatedVariable() {
void CAnimatedVariable::unregister() { void CAnimatedVariable::unregister() {
g_pAnimationManager->m_lAnimatedVariables.remove(this); g_pAnimationManager->m_lAnimatedVariables.remove(this);
m_bIsRegistered = false;
}
void CAnimatedVariable::registerVar() {
if (!m_bIsRegistered)
g_pAnimationManager->m_lAnimatedVariables.push_back(this);
m_bIsRegistered = true;
} }
int CAnimatedVariable::getDurationLeftMs() { int CAnimatedVariable::getDurationLeftMs() {
return std::max((int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0); return std::max((int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0);
} }
float CAnimatedVariable::getPercent() {
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count();
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
}

View File

@@ -21,6 +21,7 @@ class CAnimationManager;
class CWorkspace; class CWorkspace;
struct SLayerSurface; struct SLayerSurface;
struct SAnimationPropertyConfig; struct SAnimationPropertyConfig;
class CHyprRenderer;
class CAnimatedVariable { class CAnimatedVariable {
public: public:
@@ -32,6 +33,7 @@ public:
~CAnimatedVariable(); ~CAnimatedVariable();
void unregister(); void unregister();
void registerVar();
// gets the current vector value (real time) // gets the current vector value (real time)
const Vector2D& vec() const { const Vector2D& vec() const {
@@ -67,18 +69,24 @@ public:
m_vGoal = v; m_vGoal = v;
animationBegin = std::chrono::system_clock::now(); animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue; m_vBegun = m_vValue;
onAnimationBegin();
} }
void operator=(const float& v) { void operator=(const float& v) {
m_fGoal = v; m_fGoal = v;
animationBegin = std::chrono::system_clock::now(); animationBegin = std::chrono::system_clock::now();
m_fBegun = m_fValue; m_fBegun = m_fValue;
onAnimationBegin();
} }
void operator=(const CColor& v) { void operator=(const CColor& v) {
m_cGoal = v; m_cGoal = v;
animationBegin = std::chrono::system_clock::now(); animationBegin = std::chrono::system_clock::now();
m_cBegun = m_cValue; m_cBegun = m_cValue;
onAnimationBegin();
} }
// Sets the actual stored value, without affecting the goal, but resets the timer // Sets the actual stored value, without affecting the goal, but resets the timer
@@ -86,6 +94,8 @@ public:
m_vValue = v; m_vValue = v;
animationBegin = std::chrono::system_clock::now(); animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue; m_vBegun = m_vValue;
onAnimationBegin();
} }
// Sets the actual stored value, without affecting the goal, but resets the timer // Sets the actual stored value, without affecting the goal, but resets the timer
@@ -93,6 +103,8 @@ public:
m_fValue = v; m_fValue = v;
animationBegin = std::chrono::system_clock::now(); animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue; m_vBegun = m_vValue;
onAnimationBegin();
} }
// Sets the actual stored value, without affecting the goal, but resets the timer // Sets the actual stored value, without affecting the goal, but resets the timer
@@ -100,6 +112,8 @@ public:
m_cValue = v; m_cValue = v;
animationBegin = std::chrono::system_clock::now(); animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue; m_vBegun = m_vValue;
onAnimationBegin();
} }
// Sets the actual value and goal // Sets the actual value and goal
@@ -138,7 +152,7 @@ public:
return false; // just so that the warning is suppressed return false; // just so that the warning is suppressed
} }
void warp() { void warp(bool endCallback = true) {
switch (m_eVarType) { switch (m_eVarType) {
case AVARTYPE_FLOAT: { case AVARTYPE_FLOAT: {
m_fValue = m_fGoal; m_fValue = m_fGoal;
@@ -155,6 +169,9 @@ public:
default: default:
UNREACHABLE(); UNREACHABLE();
} }
if (endCallback)
onAnimationEnd();
} }
void setConfig(SAnimationPropertyConfig* pConfig) { void setConfig(SAnimationPropertyConfig* pConfig) {
@@ -167,6 +184,35 @@ public:
int getDurationLeftMs(); int getDurationLeftMs();
/* returns the spent (completion) % */
float getPercent();
/* sets a function to be ran when the animation finishes.
if an animation is not running, runs instantly.
if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnEnd(std::function<void(void* thisptr)> func, bool remove = true) {
m_fEndCallback = func;
m_bRemoveEndAfterRan = remove;
if (!isBeingAnimated())
onAnimationEnd();
}
/* sets a function to be ran when an animation is started.
if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnBegin(std::function<void(void* thisptr)> func, bool remove = true) {
m_fBeginCallback = func;
m_bRemoveBeginAfterRan = remove;
}
/* resets all callbacks. Does not call any. */
void resetAllCallbacks() {
m_fBeginCallback = nullptr;
m_fEndCallback = nullptr;
m_bRemoveBeginAfterRan = false;
m_bRemoveEndAfterRan = false;
}
private: private:
Vector2D m_vValue = Vector2D(0,0); Vector2D m_vValue = Vector2D(0,0);
@@ -189,13 +235,37 @@ private:
SAnimationPropertyConfig* m_pConfig = nullptr; SAnimationPropertyConfig* m_pConfig = nullptr;
bool m_bDummy = true; bool m_bDummy = true;
bool m_bIsRegistered = false;
std::chrono::system_clock::time_point animationBegin; std::chrono::system_clock::time_point animationBegin;
ANIMATEDVARTYPE m_eVarType = AVARTYPE_INVALID; ANIMATEDVARTYPE m_eVarType = AVARTYPE_INVALID;
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_INVALID; AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_INVALID;
bool m_bRemoveEndAfterRan = true;
bool m_bRemoveBeginAfterRan = true;
std::function<void(void* thisptr)> m_fEndCallback;
std::function<void(void* thisptr)> m_fBeginCallback;
// methods
void onAnimationEnd() {
if (m_fEndCallback) {
m_fEndCallback(this);
if (m_bRemoveEndAfterRan)
m_fEndCallback = nullptr; // reset
}
}
void onAnimationBegin() {
if (m_fBeginCallback) {
m_fBeginCallback(this);
if (m_bRemoveBeginAfterRan)
m_fBeginCallback = nullptr; // reset
}
}
friend class CAnimationManager; friend class CAnimationManager;
friend class CWorkspace; friend class CWorkspace;
friend struct SLayerSurface; friend struct SLayerSurface;
friend class CHyprRenderer;
}; };

View File

@@ -5,6 +5,31 @@
#include <sys/utsname.h> #include <sys/utsname.h>
#include <iomanip> #include <iomanip>
#if defined(__DragonFly__) || defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/sysctl.h>
# if defined(__DragonFly__)
# include <sys/kinfo.h> // struct kinfo_proc
# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
# include <sys/user.h> // struct kinfo_proc
# endif
# if defined(__NetBSD__)
# undef KERN_PROC
# define KERN_PROC KERN_PROC2
# define KINFO_PROC struct kinfo_proc2
# else
# define KINFO_PROC struct kinfo_proc
# endif
# if defined(__DragonFly__)
# define KP_PPID(kp) kp.kp_ppid
# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
# define KP_PPID(kp) kp.ki_ppid
# else
# define KP_PPID(kp) kp.p_ppid
# endif
#endif
static const float transforms[][9] = {{ static const float transforms[][9] = {{
1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
@@ -120,6 +145,9 @@ void scaleBox(wlr_box* box, float scale) {
} }
std::string removeBeginEndSpacesTabs(std::string str) { std::string removeBeginEndSpacesTabs(std::string str) {
if (str.empty())
return str;
int countBefore = 0; int countBefore = 0;
while (str[countBefore] == ' ' || str[countBefore] == '\t') { while (str[countBefore] == ' ' || str[countBefore] == '\t') {
countBefore++; countBefore++;
@@ -206,7 +234,18 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int result = INT_MAX; int result = INT_MAX;
if (in.find("special") == 0) { if (in.find("special") == 0) {
outName = "special"; outName = "special";
return SPECIAL_WORKSPACE_ID;
if (in.length() > 8) {
const auto NAME = in.substr(8);
const auto WS = g_pCompositor->getWorkspaceByName("special:" + NAME);
outName = "special:" + NAME;
return WS ? WS->m_iID : g_pCompositor->getNewSpecialID();
}
return SPECIAL_WORKSPACE_START;
} else if (in.find("name:") == 0) { } else if (in.find("name:") == 0) {
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1); const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME); const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
@@ -216,6 +255,13 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
result = WORKSPACE->m_iID; result = WORKSPACE->m_iID;
} }
outName = WORKSPACENAME; outName = WORKSPACENAME;
} else if (in.find("empty") == 0) {
int id = 0;
while (++id < INT_MAX) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0))
return id;
}
} else { } else {
if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) { if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
bool onAllMonitors = in[0] == 'e'; bool onAllMonitors = in[0] == 'e';
@@ -231,51 +277,41 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
// result now has +/- what we should move on mon // result now has +/- what we should move on mon
int remains = (int)result; int remains = (int)result;
int currentID = g_pCompositor->m_pLastMonitor->activeWorkspace;
int searchID = currentID;
while (remains != 0) { std::vector<int> validWSes;
if (remains < 0) for (auto& ws : g_pCompositor->m_vWorkspaces) {
searchID--; if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors))
else continue;
searchID++;
if (g_pCompositor->workspaceIDOutOfBounds(searchID)){ validWSes.push_back(ws->m_iID);
// means we need to wrap around }
int lowestID = 99999;
int highestID = -99999;
for (auto& w : g_pCompositor->m_vWorkspaces) { std::sort(validWSes.begin(), validWSes.end());
if (w->m_iID == SPECIAL_WORKSPACE_ID)
continue;
if (w->m_iID < lowestID) // get the offset
lowestID = w->m_iID; remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size();
if (w->m_iID > highestID) // get the current item
highestID = w->m_iID; int currentItem = -1;
} for (size_t i = 0; i < validWSes.size(); i++) {
if (validWSes[i] == g_pCompositor->m_pLastMonitor->activeWorkspace) {
if (remains < 0) currentItem = i;
searchID = highestID; break;
else
searchID = lowestID;
}
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(searchID); PWORKSPACE && PWORKSPACE->m_iID != SPECIAL_WORKSPACE_ID) {
if (onAllMonitors || PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
currentID = PWORKSPACE->m_iID;
if (remains < 0)
remains++;
else
remains--;
}
} }
} }
result = currentID; // apply
outName = g_pCompositor->getWorkspaceByID(currentID)->m_szName; currentItem += remains;
// sanitize
if (currentItem >= (int)validWSes.size()) {
currentItem = currentItem % validWSes.size();
} else if (currentItem < 0) {
currentItem = validWSes.size() + currentItem;
}
result = validWSes[currentItem];
outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName;
} else { } else {
if (in[0] == '+' || in[0] == '-') { if (in[0] == '+' || in[0] == '-') {
@@ -332,6 +368,15 @@ void logSystemInfo() {
Debug::log(LOG, "Release: %s", unameInfo.release); Debug::log(LOG, "Release: %s", unameInfo.release);
Debug::log(LOG, "Version: %s", unameInfo.version); Debug::log(LOG, "Version: %s", unameInfo.version);
Debug::log(NONE, "\n");
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
Debug::log(LOG, "GPU information:\n%s\n", GPUINFO.c_str());
if (GPUINFO.contains("NVIDIA")) {
Debug::log(WARN, "Warning: you're using an NVIDIA GPU. Make sure you follow the instructions on the wiki if anything is amiss.\n");
}
// log etc // log etc
Debug::log(LOG, "os-release:"); Debug::log(LOG, "os-release:");
@@ -348,8 +393,8 @@ void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
// Rotation + reflection // Rotation + reflection
mat[0] = x * t[0]; mat[0] = x * t[0];
mat[1] = x * t[1]; mat[1] = x * t[1];
mat[3] = y * -t[3]; mat[3] = y * t[3];
mat[4] = y * -t[4]; mat[4] = y * t[4];
// Translation // Translation
mat[2] = -copysign(1.0f, mat[0] + mat[1]); mat[2] = -copysign(1.0f, mat[0] + mat[1]);
@@ -360,6 +405,25 @@ void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
} }
int64_t getPPIDof(int64_t pid) { int64_t getPPIDof(int64_t pid) {
#if defined(KERN_PROC_PID)
int mib[] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PID,
(int)pid,
# if defined(__NetBSD__) || defined(__OpenBSD__)
sizeof(KINFO_PROC),
1,
# endif
};
u_int miblen = sizeof(mib) / sizeof(mib[0]);
KINFO_PROC kp;
size_t sz = sizeof(KINFO_PROC);
if (sysctl(mib, miblen, &kp, &sz, NULL, 0) != -1)
return KP_PPID(kp);
return 0;
#else
std::string dir = "/proc/" + std::to_string(pid) + "/status"; std::string dir = "/proc/" + std::to_string(pid) + "/status";
FILE* infile; FILE* infile;
@@ -392,4 +456,41 @@ int64_t getPPIDof(int64_t pid) {
} catch (std::exception& e) { } catch (std::exception& e) {
return 0; return 0;
} }
#endif
}
int64_t configStringToInt(const std::string& VALUE) {
if (VALUE.find("0x") == 0) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
return stol(VALUEWITHOUTHEX, nullptr, 16);
} else if (VALUE.find("rgba(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
Debug::log(WARN, "invalid length %i for rgba", VALUEWITHOUTFUNC.length());
throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)");
}
const auto RGBA = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
// now we need to RGBA -> ARGB. The config holds ARGB only.
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
} else if (VALUE.find("rgb(") == 0 && VALUE.find(")") == VALUE.length() - 1) {
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
Debug::log(WARN, "invalid length %i for rgb", VALUEWITHOUTFUNC.length());
throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)");
}
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
return RGB + 0xFF000000; // 0xFF for opaque
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
return 1;
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
return 0;
}
return stol(VALUE);
} }

View File

@@ -15,6 +15,7 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve
void logSystemInfo(); void logSystemInfo();
std::string execAndGet(const char*); std::string execAndGet(const char*);
int64_t getPPIDof(int64_t pid); int64_t getPPIDof(int64_t pid);
int64_t configStringToInt(const std::string&);
float getPlusMinusKeywordResult(std::string in, float relative); float getPlusMinusKeywordResult(std::string in, float relative);

View File

@@ -3,21 +3,30 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
void CMonitor::onConnect(bool noRule) { void CMonitor::onConnect(bool noRule) {
if (m_bEnabled) hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
hyprListener_monitorStateRequest.removeCallback();
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this);
if (m_bEnabled) {
wlr_output_enable(output, 1);
wlr_output_commit(output);
return; return;
}
szName = output->name; szName = output->name;
// get monitor rule that matches if (!wlr_backend_is_drm(output->backend))
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name); createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this); // get monitor rule that matches
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this); SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { if (monitorRule.disabled) {
wlr_output_enable_adaptive_sync(output, 1);
wlr_output_set_scale(output, 1); wlr_output_set_scale(output, 1);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
@@ -88,9 +97,7 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true; m_bEnabled = true;
wlr_output_set_scale(output, monitorRule.scale);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale); wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms
// create it in the arr // create it in the arr
vecPosition = monitorRule.offset; vecPosition = monitorRule.offset;
@@ -99,10 +106,6 @@ void CMonitor::onConnect(bool noRule) {
wlr_output_enable(output, 1); 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 // set mode, also applies
if (!noRule) if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
@@ -127,22 +130,27 @@ void CMonitor::onConnect(bool noRule) {
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering. forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
// //
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->m_pLastMonitor = this; g_pCompositor->setActiveMonitor(this);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale); wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
g_pHyprRenderer->arrangeLayersForMonitor(ID); g_pHyprRenderer->arrangeLayersForMonitor(ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); // ensure VRR (will enable if necessary)
g_pConfigManager->ensureVRR(this);
} }
void CMonitor::onDisconnect() { void CMonitor::onDisconnect() {
if (!m_bEnabled) if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
return; return;
Debug::log(LOG, "onDisconnect called for %s", output->name);
// Cleanup everything. Move windows back, snap cursor, shit. // Cleanup everything. Move windows back, snap cursor, shit.
CMonitor* BACKUPMON = nullptr; CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
@@ -152,6 +160,9 @@ void CMonitor::onDisconnect() {
} }
} }
if (g_pCompositor->m_pLastMonitor == this)
g_pCompositor->setActiveMonitor(BACKUPMON);
// remove mirror // remove mirror
if (pMirrorOf) { if (pMirrorOf) {
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; })); pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; }));
@@ -174,7 +185,7 @@ void CMonitor::onDisconnect() {
if (!BACKUPMON) { if (!BACKUPMON) {
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend."); Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
hyprListener_monitorMode.removeCallback(); hyprListener_monitorStateRequest.removeCallback();
hyprListener_monitorDestroy.removeCallback(); hyprListener_monitorDestroy.removeCallback();
g_pCompositor->m_bUnsafeState = true; g_pCompositor->m_bUnsafeState = true;
@@ -182,10 +193,8 @@ void CMonitor::onDisconnect() {
return; return;
} }
const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;
// snap cursor // 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); wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
// move workspaces // move workspaces
std::deque<CWorkspace*> wspToMove; std::deque<CWorkspace*> wspToMove;
@@ -210,13 +219,13 @@ void CMonitor::onDisconnect() {
wlr_output_commit(output); 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; })); std::erase_if(g_pCompositor->m_vWorkspaces, [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; });
Debug::log(LOG, "Removed monitor %s!", szName.c_str()); Debug::log(LOG, "Removed monitor %s!", szName.c_str());
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); 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; })); std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
} }
void CMonitor::addDamage(pixman_region32_t* rg) { void CMonitor::addDamage(pixman_region32_t* rg) {
@@ -231,12 +240,26 @@ bool CMonitor::isMirror() {
return pMirrorOf != nullptr; return pMirrorOf != nullptr;
} }
int CMonitor::findAvailableDefaultWS() {
for (size_t i = 1; i < INT32_MAX; ++i) {
if (g_pCompositor->getWorkspaceByID(i))
continue;
if (const auto BOUND = g_pConfigManager->getBoundMonitorStringForWS(std::to_string(i)); !BOUND.empty() && BOUND != szName)
continue;
return i;
}
return INT32_MAX; // shouldn't be reachable
}
void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
// Workspace // Workspace
std::string newDefaultWorkspaceName = ""; std::string newDefaultWorkspaceName = "";
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName); int64_t WORKSPACEID = monitorRule.defaultWorkspace == "" ? findAvailableDefaultWS() : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) { if (WORKSPACEID == INT_MAX || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) {
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1; WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
newDefaultWorkspaceName = std::to_string(WORKSPACEID); newDefaultWorkspaceName = std::to_string(WORKSPACEID);
@@ -297,7 +320,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = nullptr; pMirrorOf = nullptr;
// set rule // set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName); const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName, this->output->description ? this->output->description : "");
vecPosition = RULE.offset; vecPosition = RULE.offset;
@@ -318,7 +341,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
setupDefaultWS(RULE); setupDefaultWS(RULE);
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y); g_pHyprRenderer->applyMonitorRule(this, (SMonitorRule*)&RULE, true); // will apply the offset and stuff
} else { } else {
CMonitor* BACKUPMON = nullptr; CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
@@ -356,6 +379,6 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return other.get() == this; })); g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return other.get() == this; }));
} }
g_pCompositor->m_pLastMonitor = g_pCompositor->m_vMonitors.front().get(); g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front().get());
} }
} }

View File

@@ -11,7 +11,7 @@ struct SMonitorRule;
class CMonitor { class CMonitor {
public: public:
Vector2D vecPosition = Vector2D(0,0); Vector2D vecPosition = Vector2D(-1,-1); // means unset
Vector2D vecSize = Vector2D(0,0); Vector2D vecSize = Vector2D(0,0);
Vector2D vecPixelSize = Vector2D(0,0); Vector2D vecPixelSize = Vector2D(0,0);
Vector2D vecTransformedSize = Vector2D(0,0); Vector2D vecTransformedSize = Vector2D(0,0);
@@ -37,12 +37,17 @@ public:
bool scheduledRecalc = false; bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
// mirroring // mirroring
CMonitor* pMirrorOf = nullptr; CMonitor* pMirrorOf = nullptr;
std::vector<CMonitor*> mirrors; std::vector<CMonitor*> mirrors;
// for the special workspace // for the special workspace. 0 means not open.
bool specialWorkspaceOpen = false; int specialWorkspaceID = 0;
// Double-linked list because we need to have constant mem addresses for signals // 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 // We have to store pointers and use raw new/delete because they might be moved between them
@@ -51,7 +56,7 @@ public:
DYNLISTENER(monitorFrame); DYNLISTENER(monitorFrame);
DYNLISTENER(monitorDestroy); DYNLISTENER(monitorDestroy);
DYNLISTENER(monitorMode); DYNLISTENER(monitorStateRequest);
// hack: a group = workspaces on a monitor. // hack: a group = workspaces on a monitor.
// I don't really care lol :P // I don't really care lol :P
@@ -78,4 +83,5 @@ public:
private: private:
void setupDefaultWS(const SMonitorRule&); void setupDefaultWS(const SMonitorRule&);
int findAvailableDefaultWS();
}; };

View File

@@ -3,8 +3,8 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) { void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
*lx += node->pSurface->sx; *lx += node->pSurface->current.dx;
*ly += node->pSurface->sy; *ly += node->pSurface->current.dy;
if (node->offsetfn) { if (node->offsetfn) {
// This is the root node // This is the root node
@@ -178,19 +178,23 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
if (subsurface->pChild) { if (subsurface->pChild) {
const auto PNODE = subsurface->pChild; const auto PNODE = subsurface->pChild;
int lx = 0, ly = 0; const auto IT = std::find_if(SubsurfaceTree::surfaceTreeNodes.begin(), SubsurfaceTree::surfaceTreeNodes.end(), [&](const SSurfaceTreeNode& other) { return &other == PNODE; });
addSurfaceGlobalOffset(PNODE, &lx, &ly);
wlr_box extents = {lx, ly, 0, 0}; if (IT != SubsurfaceTree::surfaceTreeNodes.end()) {
if (PNODE->pSurface) { int lx = 0, ly = 0;
extents.width = PNODE->pSurface->current.width; addSurfaceGlobalOffset(PNODE, &lx, &ly);
extents.height = PNODE->pSurface->current.height;
g_pHyprRenderer->damageBox(&extents); wlr_box extents = {lx, ly, 0, 0};
if (PNODE->pSurface) {
extents.width = PNODE->pSurface->current.width;
extents.height = PNODE->pSurface->current.height;
g_pHyprRenderer->damageBox(&extents);
}
// SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
// subsurface->pChild = nullptr;
} }
//SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
//subsurface->pChild = nullptr;
} }
} }

View File

@@ -4,4 +4,5 @@
SLayerSurface::SLayerSurface() { SLayerSurface::SLayerSurface() {
alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE); alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE);
alpha.m_pLayer = this; alpha.m_pLayer = this;
alpha.registerVar();
} }

View File

@@ -70,6 +70,7 @@ struct SRenderData {
// for blurring // for blurring
bool blur = false; bool blur = false;
bool blockBlurOptimization = false;
// only for windows, not popups // only for windows, not popups
bool squishOversized = true; bool squishOversized = true;
@@ -131,6 +132,8 @@ struct SMouse {
bool virt = false; bool virt = false;
bool connected = false; // means connected to the cursor
DYNLISTENER(commitConstraint); DYNLISTENER(commitConstraint);
DYNLISTENER(destroyMouse); DYNLISTENER(destroyMouse);
@@ -143,6 +146,9 @@ struct SConstraint {
SMouse* pMouse = nullptr; SMouse* pMouse = nullptr;
wlr_pointer_constraint_v1* constraint = nullptr; wlr_pointer_constraint_v1* constraint = nullptr;
bool hintSet = false;
Vector2D positionHint; // the position hint, but will be set to the current cursor pos if not set.
DYNLISTENER(setConstraintRegion); DYNLISTENER(setConstraintRegion);
DYNLISTENER(destroyConstraint); DYNLISTENER(destroyConstraint);
@@ -326,9 +332,24 @@ struct SIMEPopup {
struct STouchDevice { struct STouchDevice {
wlr_input_device* pWlrDevice = nullptr; wlr_input_device* pWlrDevice = nullptr;
std::string name = "";
std::string boundOutput = "";
DYNLISTENER(destroy); DYNLISTENER(destroy);
bool operator==(const STouchDevice& other) { bool operator==(const STouchDevice& other) {
return pWlrDevice == other.pWlrDevice; return pWlrDevice == other.pWlrDevice;
} }
}; };
struct SSwitchDevice {
wlr_input_device* pWlrDevice = nullptr;
DYNLISTENER(destroy);
DYNLISTENER(toggle);
bool operator==(const SSwitchDevice& other) {
return pWlrDevice == other.pWlrDevice;
}
};

View File

@@ -31,6 +31,9 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
m_fAlpha.create(AVARTYPE_FLOAT, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE); m_fAlpha.create(AVARTYPE_FLOAT, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
m_fAlpha.setValueAndWarp(255.f); m_fAlpha.setValueAndWarp(255.f);
m_vRenderOffset.registerVar();
m_fAlpha.registerVar();
g_pEventManager->postEvent({"createworkspace", m_szName}, true); g_pEventManager->postEvent({"createworkspace", m_szName}, true);
} }
@@ -93,7 +96,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} }
// check LS-es // check LS-es
if (in) { if (in && !m_bIsSpecialWorkspace) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
if (!ls->fadingOut) if (!ls->fadingOut)

View File

@@ -0,0 +1,161 @@
#pragma once
#include <wayland-server.h>
typedef unsigned int xcb_atom_t;
struct xcb_icccm_wm_hints_t;
typedef struct {
/** User specified flags */
uint32_t flags;
/** User-specified position */
int32_t x, y;
/** User-specified size */
int32_t width, height;
/** Program-specified minimum size */
int32_t min_width, min_height;
/** Program-specified maximum size */
int32_t max_width, max_height;
/** Program-specified resize increments */
int32_t width_inc, height_inc;
/** Program-specified minimum aspect ratios */
int32_t min_aspect_num, min_aspect_den;
/** Program-specified maximum aspect ratios */
int32_t max_aspect_num, max_aspect_den;
/** Program-specified base size */
int32_t base_width, base_height;
/** Program-specified window gravity */
uint32_t win_gravity;
} xcb_size_hints_t;
typedef unsigned int xcb_window_t;
typedef enum xcb_stack_mode_t {
XCB_STACK_MODE_ABOVE = 0,
XCB_STACK_MODE_BELOW = 1,
XCB_STACK_MODE_TOP_IF = 2,
XCB_STACK_MODE_BOTTOM_IF = 3,
XCB_STACK_MODE_OPPOSITE = 4
} xcb_stack_mode_t;
struct wlr_xwayland {
struct wlr_xwayland_server *server;
struct wlr_xwm *xwm;
struct wlr_xwayland_cursor *cursor;
const char *display_name;
struct wl_display *wl_display;
struct wlr_compositor *compositor;
struct wlr_seat *seat;
void *data;
};
struct wlr_xwayland_surface {
xcb_window_t window_id;
struct wlr_xwm *xwm;
uint32_t surface_id;
struct wl_list link;
struct wl_list stack_link;
struct wl_list unpaired_link;
struct wlr_surface *surface;
int16_t x, y;
uint16_t width, height;
uint16_t saved_width, saved_height;
bool override_redirect;
bool mapped;
char *title;
char *_class;
char *instance;
char *role;
char *startup_id;
pid_t pid;
bool has_utf8_title;
struct wl_list children; // wlr_xwayland_surface::parent_link
struct wlr_xwayland_surface *parent;
struct wl_list parent_link; // wlr_xwayland_surface::children
xcb_atom_t *window_type;
size_t window_type_len;
xcb_atom_t *protocols;
size_t protocols_len;
uint32_t decorations;
xcb_icccm_wm_hints_t *hints;
xcb_size_hints_t *size_hints;
bool pinging;
struct wl_event_source *ping_timer;
// _NET_WM_STATE
bool modal;
bool fullscreen;
bool maximized_vert, maximized_horz;
bool minimized;
bool has_alpha;
struct {
struct wl_signal destroy;
struct wl_signal request_configure;
struct wl_signal request_move;
struct wl_signal request_resize;
struct wl_signal request_minimize;
struct wl_signal request_maximize;
struct wl_signal request_fullscreen;
struct wl_signal request_activate;
struct wl_signal map;
struct wl_signal unmap;
struct wl_signal set_title;
struct wl_signal set_class;
struct wl_signal set_role;
struct wl_signal set_parent;
struct wl_signal set_pid;
struct wl_signal set_startup_id;
struct wl_signal set_window_type;
struct wl_signal set_hints;
struct wl_signal set_decorations;
struct wl_signal set_override_redirect;
struct wl_signal set_geometry;
struct wl_signal ping_timeout;
} events;
};
struct wlr_xwayland_surface_configure_event {
struct wlr_xwayland_surface *surface;
int16_t x, y;
uint16_t width, height;
uint16_t mask; // xcb_config_window_t
};
struct wlr_xwayland_minimize_event {
struct wlr_xwayland_surface *surface;
bool minimize;
};
inline void wlr_xwayland_destroy(wlr_xwayland*) { }
inline void wlr_xwayland_surface_configure(wlr_xwayland_surface*, int, int, int, int) { }
inline bool wlr_surface_is_xwayland_surface(void*) { return false; }
inline void wlr_xwayland_surface_activate(wlr_xwayland_surface*, bool) { }
inline void wlr_xwayland_surface_restack(wlr_xwayland_surface*, int, xcb_stack_mode_t) { }
inline wlr_xwayland_surface* wlr_xwayland_surface_from_wlr_surface(void*) { return nullptr; }
inline void wlr_xwayland_surface_close(wlr_xwayland_surface*) { }
inline void wlr_xwayland_surface_set_fullscreen(wlr_xwayland_surface*, bool) { }
inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface *, bool) { }
inline bool wlr_backend_is_x11(void*) { return false; }
inline void wlr_x11_output_create(void*) { }

View File

@@ -67,10 +67,10 @@ void CHyprError::createQueued() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
#ifndef GLES2 #ifndef GLES2
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
#endif #endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);

View File

@@ -22,7 +22,6 @@
#include <filesystem> #include <filesystem>
#include <climits> #include <climits>
#if true #if true
// wlroots uses dumb-ass shit that makes it not compile on C++, let's fix that. // wlroots uses dumb-ass shit that makes it not compile on C++, let's fix that.
// https://github.com/swaywm/wlroots/issues/682 // https://github.com/swaywm/wlroots/issues/682
@@ -80,13 +79,11 @@ extern "C" {
#include <wlr/types/wlr_foreign_toplevel_management_v1.h> #include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_idle_inhibit_v1.h> #include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <wlr/xwayland.h>
#include <wlr/util/region.h> #include <wlr/util/region.h>
#include <wlr/types/wlr_tablet_pad.h> #include <wlr/types/wlr_tablet_pad.h>
#include <wlr/types/wlr_tablet_tool.h> #include <wlr/types/wlr_tablet_tool.h>
#include <wlr/types/wlr_tablet_v2.h> #include <wlr/types/wlr_tablet_v2.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <X11/Xproto.h>
#include <wlr/render/egl.h> #include <wlr/render/egl.h>
#include <wlr/render/gles2.h> #include <wlr/render/gles2.h>
#include <wlr/render/wlr_texture.h> #include <wlr/render/wlr_texture.h>
@@ -101,6 +98,19 @@ extern "C" {
#include <wlr/types/wlr_input_method_v2.h> #include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_text_input_v3.h> #include <wlr/types/wlr_text_input_v3.h>
#include <wlr/types/wlr_touch.h> #include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_switch.h>
#include <wlr/config.h>
#include <wlr/backend/headless.h>
#include <wlr/backend/multi.h>
#include <wlr/backend/wayland.h>
#include <drm_fourcc.h>
#ifndef NO_XWAYLAND
#include <wlr/backend/x11.h>
#include <wlr/xwayland.h>
#include <X11/Xproto.h>
#endif
} }
#undef delete #undef delete
@@ -121,6 +131,7 @@ extern "C" {
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
#define XWAYLAND false #define XWAYLAND false
#include "helpers/XWaylandStubs.hpp"
#else #else
#define XWAYLAND true #define XWAYLAND true
#endif #endif
@@ -128,6 +139,3 @@ extern "C" {
#include "helpers/Vector2D.hpp" #include "helpers/Vector2D.hpp"
#include "ext-workspace-unstable-v1-protocol.h" #include "ext-workspace-unstable-v1-protocol.h"
#include <algorithm>
#include <utility>

View File

@@ -69,7 +69,7 @@ SDwindleNodeData* SDwindleNodeData::getGroupVisible() {
SDwindleNodeData* current = this->pNextGroupMember; SDwindleNodeData* current = this->pNextGroupMember;
while (current != this) { while (current != this) {
if (!current->pWindow->m_bHidden) { if (!current->pWindow->isHidden()) {
return current; return current;
} }
@@ -83,11 +83,11 @@ void SDwindleNodeData::setGroupFocusedNode(SDwindleNodeData* pMember) {
SDwindleNodeData* current = this->pNextGroupMember; SDwindleNodeData* current = this->pNextGroupMember;
while (current != this) { while (current != this) {
current->pWindow->m_bHidden = current != pMember; current->pWindow->setHidden(current != pMember);
current = current->pNextGroupMember; current = current->pNextGroupMember;
} }
this->pWindow->m_bHidden = pMember != this; this->pWindow->setHidden(pMember != this);
} }
int SDwindleNodeData::getGroupMemberCount() { int SDwindleNodeData::getGroupMemberCount() {
@@ -144,9 +144,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
CMonitor* PMONITOR = nullptr; CMonitor* PMONITOR = nullptr;
if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) { if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (m->specialWorkspaceOpen) { if (m->specialWorkspaceID == pNode->workspaceID) {
PMONITOR = m.get(); PMONITOR = m.get();
break; break;
} }
@@ -188,7 +188,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID); const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID);
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && (NODESONWORKSPACE == 1 || (pNode->isGroupMember() && pNode->getGroupMemberCount() == NODESONWORKSPACE))) { if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && (NODESONWORKSPACE == 1 || (pNode->isGroupMember() && pNode->getGroupMemberCount() == NODESONWORKSPACE) || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE); PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE);
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE); PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
@@ -238,7 +238,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
} }
} }
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) { if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
// if special, we adjust the coords a bit // if special, we adjust the coords a bit
static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue; static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue;
@@ -293,7 +293,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
SDwindleNodeData* OPENINGON; SDwindleNodeData* OPENINGON;
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromCursor(); const auto MONFROMCURSOR = g_pCompositor->getMonitorFromCursor();
if (PMONITOR->ID == MONFROMCURSOR->ID && (PNODE->workspaceID == PMONITOR->activeWorkspace || (PNODE->workspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && !*PUSEACTIVE) { if (PMONITOR->ID == MONFROMCURSOR->ID && (PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal())); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
// happens on reserved area // happens on reserved area
@@ -301,7 +301,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace); OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
} else if (*PUSEACTIVE) { } else if (*PUSEACTIVE) {
if (g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow && g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) { if (g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow && g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) {
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow); OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
} else { } else {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal())); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
@@ -336,6 +336,16 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
} }
// last fail-safe to avoid duplicate fullscreens
if ((!OPENINGON || OPENINGON->pWindow == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) {
for (auto& node : m_lDwindleNodesData) {
if (node.workspaceID == PNODE->workspaceID && node.pWindow != pWindow) {
OPENINGON = &node;
break;
}
}
}
// if it's the first, it's easy. Make it fullscreen. // if it's the first, it's easy. Make it fullscreen.
if (!OPENINGON || OPENINGON->pWindow == pWindow) { if (!OPENINGON || OPENINGON->pWindow == pWindow) {
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
@@ -457,6 +467,10 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
return; return;
} }
pWindow->m_sSpecialRenderData.rounding = true;
pWindow->m_sSpecialRenderData.border = true;
pWindow->m_sSpecialRenderData.decorate = true;
if (pWindow->m_bIsFullscreen) if (pWindow->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
@@ -491,7 +505,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
} }
PNEXT->setGroupFocusedNode(PNEXT); PNEXT->setGroupFocusedNode(PNEXT);
PNEXT->pWindow->m_bHidden = false; PNEXT->pWindow->setHidden(false);
m_lDwindleNodesData.remove(*PNODE); m_lDwindleNodesData.remove(*PNODE);
@@ -563,8 +577,8 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
g_pHyprRenderer->damageMonitor(PMONITOR); g_pHyprRenderer->damageMonitor(PMONITOR);
if (PMONITOR->specialWorkspaceOpen) { if (PMONITOR->specialWorkspaceID) {
const auto TOPNODE = getMasterNodeOnWorkspace(SPECIAL_WORKSPACE_ID); const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->specialWorkspaceID);
if (TOPNODE && PMONITOR) { if (TOPNODE && PMONITOR) {
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
@@ -621,7 +635,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
const auto PNODE = getNodeFromWindow(PWINDOW); const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) { if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0)); PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
return; return;
} }
@@ -705,7 +719,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return; return;
if (on == pWindow->m_bIsFullscreen || pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (on == pWindow->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
return; // ignore return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -829,7 +843,7 @@ void CHyprDwindleLayout::toggleWindowGroup(CWindow* pWindow) {
toAddWindows.push_back(PWINDOW); toAddWindows.push_back(PWINDOW);
PWINDOW->m_bHidden = false; PWINDOW->setHidden(false);
} }
if (PHEAD->pPreviousGroupMember) if (PHEAD->pPreviousGroupMember)
@@ -997,9 +1011,9 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward, CWind
pNewNode->pWindow->m_bIsFloating = PNODE->pWindow->m_bIsFloating; pNewNode->pWindow->m_bIsFloating = PNODE->pWindow->m_bIsFloating;
if (PNODE->pWindow->m_bIsFullscreen) { if (PNODE->pWindow->m_bIsFullscreen) {
PNODE->pWindow->m_bHidden = false; PNODE->pWindow->setHidden(false);
g_pCompositor->setWindowFullscreen(PNODE->pWindow, false, PWORKSPACE->m_efFullscreenMode); g_pCompositor->setWindowFullscreen(PNODE->pWindow, false, PWORKSPACE->m_efFullscreenMode);
PNODE->pWindow->m_bHidden = true; PNODE->pWindow->setHidden(true);
g_pCompositor->setWindowFullscreen(pNewNode->pWindow, true, PWORKSPACE->m_efFullscreenMode); g_pCompositor->setWindowFullscreen(pNewNode->pWindow, true, PWORKSPACE->m_efFullscreenMode);
pNewNode->pWindow->m_vRealSize.warp(); pNewNode->pWindow->m_vRealSize.warp();
@@ -1008,6 +1022,8 @@ void CHyprDwindleLayout::switchGroupWindow(CWindow* pWindow, bool forward, CWind
pNewNode->pWindow->updateWindowDecos(); pNewNode->pWindow->updateWindowDecos();
PNODE->pWindow->updateWindowDecos(); PNODE->pWindow->updateWindowDecos();
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID));
} }
SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow) { SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow) {
@@ -1132,6 +1148,9 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
ACTIVE2->pWindow->m_vPosition = ACTIVE2->position; ACTIVE2->pWindow->m_vPosition = ACTIVE2->position;
ACTIVE2->pWindow->m_vSize = ACTIVE2->size; ACTIVE2->pWindow->m_vSize = ACTIVE2->size;
} }
g_pHyprRenderer->damageWindow(pWindow);
g_pHyprRenderer->damageWindow(pWindow2);
} }
void CHyprDwindleLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) { void CHyprDwindleLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
@@ -1181,7 +1200,7 @@ std::string CHyprDwindleLayout::getLayoutName() {
void CHyprDwindleLayout::onEnable() { void CHyprDwindleLayout::onEnable() {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->m_bHidden) if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->isHidden())
continue; continue;
onWindowCreatedTiling(w.get()); onWindowCreatedTiling(w.get());

View File

@@ -21,11 +21,17 @@ void IHyprLayout::onWindowCreated(CWindow* pWindow) {
} }
void IHyprLayout::onWindowRemoved(CWindow* pWindow) { void IHyprLayout::onWindowRemoved(CWindow* pWindow) {
if (pWindow->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
if (pWindow->m_bIsFloating) { if (pWindow->m_bIsFloating) {
onWindowRemovedFloating(pWindow); onWindowRemovedFloating(pWindow);
} else { } else {
onWindowRemovedTiling(pWindow); onWindowRemovedTiling(pWindow);
} }
if (pWindow == m_pLastTiledWindow)
m_pLastTiledWindow = nullptr;
} }
void IHyprLayout::onWindowRemovedFloating(CWindow* pWindow) { void IHyprLayout::onWindowRemovedFloating(CWindow* pWindow) {
@@ -47,7 +53,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height); pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height);
if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { // XDG windows should be fine. TODO: check for weird atoms? if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { // XDG windows should be fine. TODO: check for weird atoms?
pWindow->m_bHidden = true; pWindow->setHidden(true);
return; return;
} }
@@ -126,13 +132,12 @@ void IHyprLayout::onBeginDragWindow() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(DRAGGINGWINDOW->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(DRAGGINGWINDOW->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow) { if (PWORKSPACE->m_bHasFullscreenWindow && (!DRAGGINGWINDOW->m_bCreatedOverFullscreen || !DRAGGINGWINDOW->m_bIsFloating)) {
Debug::log(LOG, "Rejecting drag on a fullscreen workspace."); Debug::log(LOG, "Rejecting drag on a fullscreen workspace. (window under fullscreen)");
return; return;
} }
DRAGGINGWINDOW->m_vRealPosition.setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove")); g_pInputManager->setCursorImageUntilUnset("hand1");
DRAGGINGWINDOW->m_vRealSize.setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove"));
DRAGGINGWINDOW->m_bDraggingTiled = false; DRAGGINGWINDOW->m_bDraggingTiled = false;
@@ -175,15 +180,20 @@ void IHyprLayout::onBeginDragWindow() {
void IHyprLayout::onEndDragWindow() { void IHyprLayout::onEndDragWindow() {
const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow;
g_pInputManager->unsetCursorImage();
if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW))
return; return;
if (DRAGGINGWINDOW->m_bDraggingTiled) { if (DRAGGINGWINDOW->m_bDraggingTiled) {
DRAGGINGWINDOW->m_bIsFloating = false; DRAGGINGWINDOW->m_bIsFloating = false;
g_pInputManager->refocus();
changeWindowFloatingMode(DRAGGINGWINDOW); changeWindowFloatingMode(DRAGGINGWINDOW);
} }
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
g_pCompositor->focusWindow(DRAGGINGWINDOW);
} }
void IHyprLayout::onMouseMove(const Vector2D& mousePos) { void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
@@ -191,10 +201,13 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
// Window invalid or drag begin size 0,0 meaning we rejected it. // Window invalid or drag begin size 0,0 meaning we rejected it.
if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) { if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) {
onEndDragWindow();
g_pInputManager->currentlyDraggedWindow = nullptr; g_pInputManager->currentlyDraggedWindow = nullptr;
return; return;
} }
const auto SPECIAL = g_pCompositor->isWorkspaceSpecial(DRAGGINGWINDOW->m_iWorkspaceID);
const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y); const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y);
const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y); const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y);
@@ -208,7 +221,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
if (g_pInputManager->dragMode == MBIND_MOVE) { if (g_pInputManager->dragMode == MBIND_MOVE) {
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA);
if (*PANIMATE) {
DRAGGINGWINDOW->m_vRealPosition = m_vBeginDragPositionXY + DELTA;
} else {
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA);
}
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
} else if (g_pInputManager->dragMode == MBIND_RESIZE) { } else if (g_pInputManager->dragMode == MBIND_RESIZE) {
@@ -256,7 +274,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
// and check its monitor // and check its monitor
const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle); const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle);
if (PMONITOR) { if (PMONITOR && !SPECIAL) {
DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID; DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID;
DRAGGINGWINDOW->moveToWorkspace(PMONITOR->activeWorkspace); DRAGGINGWINDOW->moveToWorkspace(PMONITOR->activeWorkspace);
@@ -282,20 +300,26 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
const auto TILED = isWindowTiled(pWindow); const auto TILED = isWindowTiled(pWindow);
// event
g_pEventManager->postEvent(SHyprIPCEvent{ "changefloatingmode", getFormat("%x,%d", pWindow, (int)TILED) });
if (!TILED) { if (!TILED) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f); const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID; pWindow->m_iMonitorID = PNEWMON->ID;
pWindow->moveToWorkspace(PNEWMON->activeWorkspace); pWindow->moveToWorkspace(PNEWMON->activeWorkspace);
// save real pos cuz the func applies the default 5,5 mid // save real pos cuz the func applies the default 5,5 mid
const auto PSAVEDPOS = pWindow->m_vRealPosition.vec(); const auto PSAVEDPOS = pWindow->m_vRealPosition.goalv();
const auto PSAVEDSIZE = pWindow->m_vRealSize.vec(); const auto PSAVEDSIZE = pWindow->m_vRealSize.goalv();
// if the window is pseudo, update its size // if the window is pseudo, update its size
pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec(); pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingSize = PSAVEDSIZE; pWindow->m_vLastFloatingSize = PSAVEDSIZE;
// move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back.
pWindow->m_vPosition = Vector2D(-999999, -999999);
onWindowCreatedTiling(pWindow); onWindowCreatedTiling(pWindow);
pWindow->m_vRealPosition.setValue(PSAVEDPOS); pWindow->m_vRealPosition.setValue(PSAVEDPOS);
@@ -303,20 +327,26 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
// fix pseudo leaving artifacts // fix pseudo leaving artifacts
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
} else {
pWindow->m_vSize = pWindow->m_vRealSize.vec();
pWindow->m_vPosition = pWindow->m_vRealPosition.vec();
if (pWindow == g_pCompositor->m_pLastWindow)
m_pLastTiledWindow = pWindow;
} else {
onWindowRemovedTiling(pWindow); onWindowRemovedTiling(pWindow);
g_pCompositor->moveWindowToTop(pWindow); g_pCompositor->moveWindowToTop(pWindow);
pWindow->m_vRealPosition = pWindow->m_vRealPosition.vec() + (pWindow->m_vRealSize.vec() - pWindow->m_vLastFloatingSize) / 2.f; pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f;
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
pWindow->m_sSpecialRenderData.rounding = true; pWindow->m_sSpecialRenderData.rounding = true;
if (pWindow == m_pLastTiledWindow)
m_pLastTiledWindow = nullptr;
} }
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
@@ -339,3 +369,59 @@ void IHyprLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) {
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
} }
void IHyprLayout::onWindowFocusChange(CWindow* pNewFocus) {
m_pLastTiledWindow = pNewFocus && !pNewFocus->m_bIsFloating ? pNewFocus : m_pLastTiledWindow;
}
CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
// although we don't expect nullptrs here, let's verify jic
if (!pWindow)
return nullptr;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
// first of all, if this is a fullscreen workspace,
if (PWORKSPACE->m_bHasFullscreenWindow)
return g_pCompositor->getFullscreenWindowOnWorkspace(pWindow->m_iWorkspaceID);
if (pWindow->m_bIsFloating) {
// find whether there is a floating window below this one
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus && !w->m_bNoFocus) {
if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, w->m_vPosition.y + w->m_vSize.y)) {
return w.get();
}
}
}
// let's try the last tiled window.
if (m_pLastTiledWindow && m_pLastTiledWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID)
return m_pLastTiledWindow;
// if we don't, let's try to find any window that is in the middle
if (const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(pWindow->m_vRealPosition.goalv() + pWindow->m_vRealSize.goalv() / 2.f); PWINDOWCANDIDATE)
return PWINDOWCANDIDATE;
// if not, floating window
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus && !w->m_bNoFocus)
return w.get();
}
// if there is no candidate, too bad
return nullptr;
}
// if it was a tiled window, we first try to find the window that will replace it.
const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(pWindow->m_vRealPosition.goalv() + pWindow->m_vRealSize.goalv() / 2.f);
if (!PWINDOWCANDIDATE || pWindow == PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bIsMapped || PWINDOWCANDIDATE->isHidden() || PWINDOWCANDIDATE->m_bX11ShouldntFocus || PWINDOWCANDIDATE->m_iX11Type == 2 || PWINDOWCANDIDATE->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
return nullptr;
return PWINDOWCANDIDATE;
}
IHyprLayout::~IHyprLayout() {
}

View File

@@ -16,6 +16,7 @@ enum eFullscreenMode : uint8_t;
interface IHyprLayout { interface IHyprLayout {
public: public:
virtual ~IHyprLayout() = 0;
virtual void onEnable() = 0; virtual void onEnable() = 0;
virtual void onDisable() = 0; virtual void onDisable() = 0;
@@ -123,10 +124,22 @@ public:
*/ */
virtual std::string getLayoutName() = 0; virtual std::string getLayoutName() = 0;
/*
Called for getting the next candidate for a focus
*/
virtual CWindow* getNextWindowCandidate(CWindow*);
/*
Internal: called when window focus changes
*/
virtual void onWindowFocusChange(CWindow*);
private: private:
Vector2D m_vBeginDragXY; Vector2D m_vBeginDragXY;
Vector2D m_vLastDragXY; Vector2D m_vLastDragXY;
Vector2D m_vBeginDragPositionXY; Vector2D m_vBeginDragPositionXY;
Vector2D m_vBeginDragSizeXY; Vector2D m_vBeginDragSizeXY;
int m_iGrabbedCorner = 0; int m_iGrabbedCorner = 0;
CWindow* m_pLastTiledWindow = nullptr;
}; };

View File

@@ -20,6 +20,38 @@ int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) {
return no; return no;
} }
int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) {
int no = 0;
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == ws && n.isMaster)
no++;
}
return no;
}
SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) {
for (auto& n : m_lMasterWorkspacesData) {
if (n.workspaceID == ws)
return &n;
}
//create on the fly if it doesn't exist yet
const auto PWORKSPACEDATA = &m_lMasterWorkspacesData.emplace_back();
PWORKSPACEDATA->workspaceID = ws;
const auto orientation = &g_pConfigManager->getConfigValuePtr("master:orientation")->strValue;
if (*orientation == "top") {
PWORKSPACEDATA->orientation = ORIENTATION_TOP;
} else if (*orientation == "right") {
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
} else if (*orientation == "bottom") {
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
} else {
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
}
return PWORKSPACEDATA;
}
std::string CHyprMasterLayout::getLayoutName() { std::string CHyprMasterLayout::getLayoutName() {
return "Master"; return "Master";
} }
@@ -101,21 +133,38 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
if (!PNODE) if (!PNODE)
return; return;
pWindow->m_sSpecialRenderData.rounding = true;
pWindow->m_sSpecialRenderData.border = true;
pWindow->m_sSpecialRenderData.decorate = true;
if (pWindow->m_bIsFullscreen) if (pWindow->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
if (PNODE->isMaster) { const auto MASTERSLEFT = getMastersOnWorkspace(PNODE->workspaceID);
if (PNODE->isMaster && MASTERSLEFT < 2) {
// find new one // find new one
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
if (!nd.isMaster) { if (!nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
nd.isMaster = true; nd.isMaster = true;
break; break;
} }
} }
} }
const auto WORKSPACEID = PNODE->workspaceID;
m_lMasterNodesData.remove(*PNODE); m_lMasterNodesData.remove(*PNODE);
if (getMastersOnWorkspace(WORKSPACEID) == getNodesOnWorkspace(WORKSPACEID) && MASTERSLEFT > 1) {
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->workspaceID == WORKSPACEID) {
it->isMaster = false;
break;
}
}
}
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->m_iMonitorID);
} }
@@ -128,8 +177,8 @@ void CHyprMasterLayout::recalculateMonitor(const int& monid) {
g_pHyprRenderer->damageMonitor(PMONITOR); g_pHyprRenderer->damageMonitor(PMONITOR);
if (PMONITOR->specialWorkspaceOpen) { if (PMONITOR->specialWorkspaceID) {
calculateWorkspace(SPECIAL_WORKSPACE_ID); calculateWorkspace(PMONITOR->specialWorkspaceID);
} }
if (PWORKSPACE->m_bHasFullscreenWindow) { if (PWORKSPACE->m_bHasFullscreenWindow) {
@@ -162,6 +211,8 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (!PWORKSPACE) if (!PWORKSPACE)
return; return;
const auto PWORKSPACEDATA = getMasterWorkspaceData(ws);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PMASTERNODE = getMasterNodeOnWorkspace(PWORKSPACE->m_iID); const auto PMASTERNODE = getMasterNodeOnWorkspace(PWORKSPACE->m_iID);
@@ -169,43 +220,129 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (!PMASTERNODE) if (!PMASTERNODE)
return; return;
const auto MASTERS = getMastersOnWorkspace(PWORKSPACE->m_iID);
//compute placement of master window(s)
if (getNodesOnWorkspace(PWORKSPACE->m_iID) < 2) { if (getNodesOnWorkspace(PWORKSPACE->m_iID) < 2) {
PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition; 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); PMASTERNODE->size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y);
applyNodeDataToWindow(PMASTERNODE); applyNodeDataToWindow(PMASTERNODE);
return; return;
} else { } else if (PWORKSPACEDATA->orientation == ORIENTATION_LEFT || PWORKSPACEDATA->orientation == ORIENTATION_RIGHT) {
PMASTERNODE->position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition; float heightLeft = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y;
PMASTERNODE->size = Vector2D((PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y); int nodesLeft = MASTERS;
} float nextY = 0;
const float WIDTH = (PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) * PMASTERNODE->percMaster;
const auto SLAVESIZE = 1.f / (getNodesOnWorkspace(PWORKSPACE->m_iID) - 1) * (PMASTERNODE->size.y); for (auto& n : m_lMasterNodesData) {
int slavesDone = 0; if (n.workspaceID == PWORKSPACE->m_iID && n.isMaster) {
if (PWORKSPACEDATA->orientation == ORIENTATION_RIGHT) {
n.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(PMONITOR->vecSize.x - WIDTH, nextY);
} else {
n.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(0, nextY);
}
float HEIGHT = nodesLeft > 1 ? heightLeft / nodesLeft * n.percSize : heightLeft;
if (HEIGHT > heightLeft * 0.9f && nodesLeft > 1)
HEIGHT = heightLeft * 0.9f;
n.size = Vector2D(WIDTH, HEIGHT);
for (auto& nd : m_lMasterNodesData) { nodesLeft--;
if (nd.workspaceID != PWORKSPACE->m_iID) heightLeft -= HEIGHT;
continue; nextY += HEIGHT;
if (nd == *PMASTERNODE) { applyNodeDataToWindow(&n);
applyNodeDataToWindow(PMASTERNODE); }
continue;
} }
} else if (PWORKSPACEDATA->orientation == ORIENTATION_TOP || PWORKSPACEDATA->orientation == ORIENTATION_BOTTOM) {
float widthLeft = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x;
int nodesLeft = MASTERS;
float nextX = 0;
const float HEIGHT = (PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y) * PMASTERNODE->percMaster;
nd.position = Vector2D(PMASTERNODE->size.x + PMASTERNODE->position.x, slavesDone * SLAVESIZE + PMASTERNODE->position.y); for (auto& n : m_lMasterNodesData) {
nd.size = Vector2D(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x - PMASTERNODE->size.x, SLAVESIZE); if (n.workspaceID == PWORKSPACE->m_iID && n.isMaster) {
if (PWORKSPACEDATA->orientation == ORIENTATION_BOTTOM) {
n.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(nextX,PMONITOR->vecSize.y - HEIGHT - PMONITOR->vecReservedBottomRight.y);
} else {
n.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(nextX, 0);
}
float WIDTH = nodesLeft > 1 ? widthLeft / nodesLeft * n.percSize : widthLeft;
if (WIDTH > widthLeft * 0.9f && nodesLeft > 1)
WIDTH = widthLeft * 0.9f;
n.size = Vector2D(WIDTH, HEIGHT);
slavesDone++; nodesLeft--;
widthLeft -= WIDTH;
nextX += WIDTH;
applyNodeDataToWindow(&nd); applyNodeDataToWindow(&n);
}
}
} }
//compute placement of slave window(s)
int slavesLeft = getNodesOnWorkspace(PWORKSPACE->m_iID) - MASTERS;
if (PWORKSPACEDATA->orientation == ORIENTATION_LEFT || PWORKSPACEDATA->orientation == ORIENTATION_RIGHT) {
float heightLeft = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y;
float nextY = 0;
const float WIDTH = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x - PMASTERNODE->size.x;
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster)
continue;
if (PWORKSPACEDATA->orientation == ORIENTATION_LEFT) {
nd.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(PMASTERNODE->percMaster * (PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x), nextY);
} else {
nd.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(0, nextY);
}
float HEIGHT = slavesLeft > 1 ? heightLeft / slavesLeft * nd.percSize : heightLeft;
if (HEIGHT > heightLeft * 0.9f && slavesLeft > 1)
HEIGHT = heightLeft * 0.9f;
nd.size = Vector2D(WIDTH, HEIGHT);
slavesLeft--;
heightLeft -= HEIGHT;
nextY += HEIGHT;
applyNodeDataToWindow(&nd);
}
} else if (PWORKSPACEDATA->orientation == ORIENTATION_TOP || PWORKSPACEDATA->orientation == ORIENTATION_BOTTOM) {
float widthLeft = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PMONITOR->vecReservedTopLeft.x;
float nextX = 0;
const float HEIGHT = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y - PMASTERNODE->size.y;
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster)
continue;
if (PWORKSPACEDATA->orientation == ORIENTATION_TOP) {
nd.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(nextX, PMASTERNODE->percMaster * (PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PMONITOR->vecReservedTopLeft.y));
} else {
nd.position = PMONITOR->vecReservedTopLeft + PMONITOR->vecPosition + Vector2D(nextX, 0);
}
float WIDTH = slavesLeft > 1 ? widthLeft / slavesLeft * nd.percSize : widthLeft;
if (WIDTH > widthLeft * 0.9f && slavesLeft > 1)
WIDTH = widthLeft * 0.9f;
nd.size = Vector2D(WIDTH, HEIGHT);
slavesLeft--;
widthLeft -= WIDTH;
nextX += WIDTH;
applyNodeDataToWindow(&nd);
}
}
} }
void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
CMonitor* PMONITOR = nullptr; CMonitor* PMONITOR = nullptr;
if (pNode->workspaceID == SPECIAL_WORKSPACE_ID) { if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (m->specialWorkspaceOpen) { if (m->specialWorkspaceID == pNode->workspaceID) {
PMONITOR = m.get(); PMONITOR = m.get();
break; break;
} }
@@ -244,7 +381,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
auto calcPos = PWINDOW->m_vPosition + Vector2D(*PBORDERSIZE, *PBORDERSIZE); auto calcPos = PWINDOW->m_vPosition + Vector2D(*PBORDERSIZE, *PBORDERSIZE);
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE); auto calcSize = PWINDOW->m_vSize - Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
if (*PNOGAPSWHENONLY && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) { if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE); PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE);
PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE); PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
@@ -270,7 +407,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
calcPos = calcPos + OFFSETTOPLEFT; calcPos = calcPos + OFFSETTOPLEFT;
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT; calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) { if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue; static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue;
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f; PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
@@ -309,13 +446,12 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
const auto PNODE = getNodeFromWindow(PWINDOW); const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) { if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0)); PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
return; return;
} }
// get master // get monitor
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2) if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2)
@@ -323,11 +459,24 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
m_bForceWarps = true; m_bForceWarps = true;
float delta = pixResize.x / PMONITOR->vecSize.x; double delta = pixResize.x / PMONITOR->vecSize.x;
PMASTER->percMaster += delta; for (auto& n : m_lMasterNodesData) {
if (n.isMaster && n.workspaceID == PMONITOR->activeWorkspace)
n.percMaster = std::clamp(n.percMaster + delta, 0.05, 0.95);
}
std::clamp(PMASTER->percMaster, 0.05f, 0.95f); // check the up/down resize
if (pixResize.y != 0) {
if (PNODE->isMaster && getMastersOnWorkspace(PNODE->workspaceID) > 1) {
// check master size
const auto SIZEY = (PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / getMastersOnWorkspace(PNODE->workspaceID);
PNODE->percSize = std::clamp(PNODE->percSize + pixResize.y / SIZEY, 0.05, 1.95);
} else if (!PNODE->isMaster && (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) - getMastersOnWorkspace(PNODE->workspaceID)) > 1) {
const auto SIZEY = (PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / getNodesOnWorkspace(PNODE->workspaceID);
PNODE->percSize = std::clamp(PNODE->percSize + pixResize.y / SIZEY, 0.05, 1.95);
}
}
recalculateMonitor(PMONITOR->ID); recalculateMonitor(PMONITOR->ID);
@@ -338,7 +487,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return; return;
if (on == pWindow->m_bIsFullscreen || pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (on == pWindow->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
return; // ignore return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -433,6 +582,8 @@ void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
if (!PNODE2 || !PNODE) if (!PNODE2 || !PNODE)
return; return;
const auto inheritFullscreen = prepareLoseFocus(pWindow);
if (PNODE->workspaceID != PNODE2->workspaceID) { if (PNODE->workspaceID != PNODE2->workspaceID) {
std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID); std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID);
std::swap(pWindow2->m_iWorkspaceID, pWindow->m_iWorkspaceID); std::swap(pWindow2->m_iWorkspaceID, pWindow->m_iWorkspaceID);
@@ -445,6 +596,11 @@ void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->m_iMonitorID);
if (PNODE2->workspaceID != PNODE->workspaceID) if (PNODE2->workspaceID != PNODE->workspaceID)
recalculateMonitor(pWindow2->m_iMonitorID); recalculateMonitor(pWindow2->m_iMonitorID);
g_pHyprRenderer->damageWindow(pWindow);
g_pHyprRenderer->damageWindow(pWindow2);
prepareNewFocus(pWindow2, inheritFullscreen);
} }
void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) { void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
@@ -499,14 +655,14 @@ CWindow* CHyprMasterLayout::getNextWindow(CWindow* pWindow, bool next) {
} }
} else { } else {
if (PNODE->isMaster) { if (PNODE->isMaster) {
// focus the first non master // focus the last non master
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) { for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->pWindow != pWindow && it->workspaceID == pWindow->m_iWorkspaceID) { if (it->pWindow != pWindow && it->workspaceID == pWindow->m_iWorkspaceID) {
return it->pWindow; return it->pWindow;
} }
} }
} else { } else {
// focus next // focus previous
bool reached = false; bool reached = false;
bool found = false; bool found = false;
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) { for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
@@ -531,41 +687,115 @@ CWindow* CHyprMasterLayout::getNextWindow(CWindow* pWindow, bool next) {
return nullptr; return nullptr;
} }
bool CHyprMasterLayout::prepareLoseFocus(CWindow* pWindow) {
if (!pWindow)
return false;
//if the current window is fullscreen, make it normal again if we are about to lose focus
if (pWindow->m_bIsFullscreen) {
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
static auto *const INHERIT = &g_pConfigManager->getConfigValuePtr("master:inherit_fullscreen")->intValue;
return *INHERIT == 1;
}
return false;
}
void CHyprMasterLayout::prepareNewFocus(CWindow* pWindow, bool inheritFullscreen) {
if (!pWindow)
return;
if (inheritFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, true, FULLSCREEN_MAXIMIZED);
}
std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::string message) { std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::string message) {
auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) { auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) {
if (!g_pCompositor->windowValidMapped(PWINDOWTOCHANGETO)) if (!g_pCompositor->windowValidMapped(PWINDOWTOCHANGETO))
return; return;
g_pCompositor->focusWindow(PWINDOWTOCHANGETO); g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f; g_pCompositor->warpCursorTo(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") { if (message == "swapwithmaster") {
const auto PWINDOW = header.pWindow; const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
if (!isWindowTiled(PWINDOW)) if (!isWindowTiled(PWINDOW))
return 0; return 0;
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID); const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
if (!PMASTER || PMASTER->pWindow == PWINDOW) if (!PMASTER)
return 0; return 0;
switchWindows(PWINDOW, PMASTER->pWindow);
switchToWindow(PWINDOW); if (PMASTER->pWindow != PWINDOW) {
switchWindows(PWINDOW, PMASTER->pWindow);
switchToWindow(PWINDOW);
} else {
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) {
switchWindows(n.pWindow, PMASTER->pWindow);
switchToWindow(n.pWindow);
break;
}
}
}
return 0;
} else if (message == "focusmaster") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
if (!PMASTER)
return 0;
if (PMASTER->pWindow != PWINDOW) {
switchToWindow(PMASTER->pWindow);
prepareNewFocus(PMASTER->pWindow, inheritFullscreen);
} else {
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) {
switchToWindow(n.pWindow);
prepareNewFocus(n.pWindow, inheritFullscreen);
break;
}
}
}
return 0; return 0;
} else if (message == "cyclenext") { } else if (message == "cyclenext") {
const auto PWINDOW = header.pWindow; const auto PWINDOW = header.pWindow;
switchToWindow(getNextWindow(PWINDOW, true)); if (!PWINDOW)
return 0;
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
const auto PNEXTWINDOW = getNextWindow(PWINDOW, true);
switchToWindow(PNEXTWINDOW);
prepareNewFocus(PNEXTWINDOW, inheritFullscreen);
} else if (message == "cycleprev") { } else if (message == "cycleprev") {
const auto PWINDOW = header.pWindow; const auto PWINDOW = header.pWindow;
switchToWindow(getNextWindow(PWINDOW, false)); if (!PWINDOW)
return 0;
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
const auto PPREVWINDOW = getNextWindow(PWINDOW, true);
switchToWindow(PPREVWINDOW);
prepareNewFocus(PPREVWINDOW, inheritFullscreen);
} else if (message == "swapnext") { } else if (message == "swapnext") {
if (!g_pCompositor->windowValidMapped(header.pWindow)) if (!g_pCompositor->windowValidMapped(header.pWindow))
return 0; return 0;
@@ -578,6 +808,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true); const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true);
if (PWINDOWTOSWAPWITH) { if (PWINDOWTOSWAPWITH) {
prepareLoseFocus(header.pWindow);
switchWindows(header.pWindow, PWINDOWTOSWAPWITH); switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
g_pCompositor->focusWindow(header.pWindow); g_pCompositor->focusWindow(header.pWindow);
} }
@@ -593,9 +824,127 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false); const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false);
if (PWINDOWTOSWAPWITH) { if (PWINDOWTOSWAPWITH) {
prepareLoseFocus(header.pWindow);
switchWindows(header.pWindow, PWINDOWTOSWAPWITH); switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
g_pCompositor->focusWindow(header.pWindow); g_pCompositor->focusWindow(header.pWindow);
} }
} else if (message == "addmaster") {
if (!g_pCompositor->windowValidMapped(header.pWindow))
return 0;
if (header.pWindow->m_bIsFloating)
return 0;
const auto PNODE = getNodeFromWindow(header.pWindow);
const auto WINDOWS = getNodesOnWorkspace(header.pWindow->m_iWorkspaceID);
const auto MASTERS = getMastersOnWorkspace(header.pWindow->m_iWorkspaceID);
if (MASTERS + 2 > WINDOWS)
return 0;
prepareLoseFocus(header.pWindow);
if (!PNODE || PNODE->isMaster) {
// first non-master node
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == header.pWindow->m_iWorkspaceID && !n.isMaster) {
n.isMaster = true;
break;
}
}
} else {
PNODE->isMaster = true;
}
recalculateMonitor(header.pWindow->m_iMonitorID);
} else if (message == "removemaster") {
if (!g_pCompositor->windowValidMapped(header.pWindow))
return 0;
if (header.pWindow->m_bIsFloating)
return 0;
const auto PNODE = getNodeFromWindow(header.pWindow);
const auto WINDOWS = getNodesOnWorkspace(header.pWindow->m_iWorkspaceID);
const auto MASTERS = getMastersOnWorkspace(header.pWindow->m_iWorkspaceID);
if (WINDOWS < 2 || MASTERS < 2)
return 0;
prepareLoseFocus(header.pWindow);
if (!PNODE || !PNODE->isMaster) {
// first non-master node
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->workspaceID == header.pWindow->m_iWorkspaceID && it->isMaster) {
it->isMaster = false;
break;
}
}
} else {
PNODE->isMaster = false;
}
recalculateMonitor(header.pWindow->m_iMonitorID);
} else if (message == "orientationleft" || message == "orientationright" || message == "orientationtop" || message == "orientationbottom") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
prepareLoseFocus(PWINDOW);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID);
if (message == "orientationleft")
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
else if (message == "orientationright")
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
else if (message == "orientationtop")
PWORKSPACEDATA->orientation = ORIENTATION_TOP;
else if (message == "orientationbottom")
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
recalculateMonitor(header.pWindow->m_iMonitorID);
} else if (message == "orientationnext") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
prepareLoseFocus(PWINDOW);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID);
if (PWORKSPACEDATA->orientation == ORIENTATION_BOTTOM) {
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
} else {
PWORKSPACEDATA->orientation = (eOrientation) (PWORKSPACEDATA->orientation + 1);
}
recalculateMonitor(header.pWindow->m_iMonitorID);
} else if (message == "orientationprev") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
prepareLoseFocus(PWINDOW);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID);
if (PWORKSPACEDATA->orientation == ORIENTATION_LEFT) {
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
} else {
PWORKSPACEDATA->orientation = (eOrientation) (PWORKSPACEDATA->orientation - 1);
}
recalculateMonitor(header.pWindow->m_iMonitorID);
} }
return 0; return 0;
@@ -603,7 +952,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
void CHyprMasterLayout::onEnable() { void CHyprMasterLayout::onEnable() {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->m_bHidden) if (w->m_bIsFloating || !w->m_bMappedX11 || !w->m_bIsMapped || w->isHidden())
continue; continue;
onWindowCreatedTiling(w.get()); onWindowCreatedTiling(w.get());

View File

@@ -1,11 +1,20 @@
#pragma once #pragma once
#include "IHyprLayout.hpp" #include "IHyprLayout.hpp"
#include <vector>
#include <list> #include <list>
#include <deque> #include <deque>
enum eFullscreenMode : uint8_t; enum eFullscreenMode : uint8_t;
//orientation determines which side of the screen the master area resides
enum eOrientation : uint8_t {
ORIENTATION_LEFT = 0,
ORIENTATION_TOP,
ORIENTATION_RIGHT,
ORIENTATION_BOTTOM
};
struct SMasterNodeData { struct SMasterNodeData {
bool isMaster = false; bool isMaster = false;
float percMaster = 0.5f; float percMaster = 0.5f;
@@ -15,6 +24,8 @@ struct SMasterNodeData {
Vector2D position; Vector2D position;
Vector2D size; Vector2D size;
float percSize = 1.f; // size multiplier for resizing children
int workspaceID = -1; int workspaceID = -1;
bool operator==(const SMasterNodeData& rhs) { bool operator==(const SMasterNodeData& rhs) {
@@ -22,6 +33,15 @@ struct SMasterNodeData {
} }
}; };
struct SMasterWorkspaceData {
int workspaceID = -1;
eOrientation orientation = ORIENTATION_LEFT;
bool operator==(const SMasterWorkspaceData& rhs) {
return workspaceID == rhs.workspaceID;
}
};
class CHyprMasterLayout : public IHyprLayout { class CHyprMasterLayout : public IHyprLayout {
public: public:
virtual void onWindowCreatedTiling(CWindow*); virtual void onWindowCreatedTiling(CWindow*);
@@ -42,7 +62,8 @@ public:
private: private:
std::list<SMasterNodeData> m_lMasterNodesData; std::list<SMasterNodeData> m_lMasterNodesData;
std::vector<SMasterWorkspaceData> m_lMasterWorkspacesData;
bool m_bForceWarps = false; bool m_bForceWarps = false;
@@ -50,8 +71,13 @@ private:
void applyNodeDataToWindow(SMasterNodeData*); void applyNodeDataToWindow(SMasterNodeData*);
SMasterNodeData* getNodeFromWindow(CWindow*); SMasterNodeData* getNodeFromWindow(CWindow*);
SMasterNodeData* getMasterNodeOnWorkspace(const int&); SMasterNodeData* getMasterNodeOnWorkspace(const int&);
SMasterWorkspaceData* getMasterWorkspaceData(const int&);
void calculateWorkspace(const int&); void calculateWorkspace(const int&);
CWindow* getNextWindow(CWindow*, bool); CWindow* getNextWindow(CWindow*, bool);
int getMastersOnWorkspace(const int&);
bool prepareLoseFocus(CWindow*);
void prepareNewFocus(CWindow*, bool inherit_fullscreen);
friend struct SMasterNodeData; friend struct SMasterNodeData;
friend struct SMasterWorkspaceData;
}; };

View File

@@ -5,10 +5,6 @@
#include "init/initHelpers.hpp" #include "init/initHelpers.hpp"
#include <iostream> #include <iostream>
// I am a bad bad boy and have used some global vars here,
// just for this file
bool ignoreSudo = false;
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (!getenv("XDG_RUNTIME_DIR")) if (!getenv("XDG_RUNTIME_DIR"))
@@ -19,9 +15,12 @@ int main(int argc, char** argv) {
for (auto i = 0; i < argc; ++i) for (auto i = 0; i < argc; ++i)
cmd += std::string(i == 0 ? "" : " ") + argv[i]; cmd += std::string(i == 0 ? "" : " ") + argv[i];
setenv("HYPRLAND_CMD", cmd.c_str(), 1); setenv("HYPRLAND_CMD", cmd.c_str(), 1);
setenv("XDG_BACKEND", "wayland", 1);
setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 0);
// parse some args // parse some args
std::string configPath; std::string configPath;
bool ignoreSudo = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--i-am-really-stupid")) if (!strcmp(argv[i], "--i-am-really-stupid"))
ignoreSudo = true; ignoreSudo = true;

View File

@@ -21,18 +21,20 @@ void CAnimationManager::addBezierWithName(std::string name, const Vector2D& p1,
void CAnimationManager::tick() { void CAnimationManager::tick() {
bool animationsDisabled = false; bool animGlobalDisabled = false;
static auto *const PANIMENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue; static auto *const PANIMENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue;
if (!*PANIMENABLED) if (!*PANIMENABLED)
animationsDisabled = true; animGlobalDisabled = true;
static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto *const PSHADOWSENABLED = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; static auto *const PSHADOWSENABLED = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
const auto DEFAULTBEZIER = m_mBezierCurves.find("default"); const auto DEFAULTBEZIER = m_mBezierCurves.find("default");
std::vector<CAnimatedVariable*> animationEndedVars;
for (auto& av : m_lAnimatedVariables) { for (auto& av : m_lAnimatedVariables) {
// first of all, check if we need to update it at all // first of all, check if we need to update it at all
@@ -40,27 +42,25 @@ void CAnimationManager::tick() {
continue; continue;
if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) { if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) {
av->warp(); av->warp(false);
continue; continue;
} }
// get speed
const auto SPEED = av->m_pConfig->pValues->internalSpeed;
// get the spent % (0 - 1) // get the spent % (0 - 1)
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - av->animationBegin).count(); const float SPENT = av->getPercent();
const float SPENT = std::clamp((DURATIONPASSED / 100.f) / SPEED, 0.f, 1.f);
// window stuff // window stuff
const auto PWINDOW = (CWindow*)av->m_pWindow; const auto PWINDOW = (CWindow*)av->m_pWindow;
const auto PWORKSPACE = (CWorkspace*)av->m_pWorkspace; const auto PWORKSPACE = (CWorkspace*)av->m_pWorkspace;
const auto PLAYER = (SLayerSurface*)av->m_pLayer; const auto PLAYER = (SLayerSurface*)av->m_pLayer;
CMonitor* PMONITOR = nullptr; CMonitor* PMONITOR = nullptr;
bool animationsDisabled = animGlobalDisabled;
wlr_box WLRBOXPREV = {0,0,0,0}; wlr_box WLRBOXPREV = {0,0,0,0};
if (PWINDOW) { if (PWINDOW) {
WLRBOXPREV = PWINDOW->getFullWindowBoundingBox(); WLRBOXPREV = PWINDOW->getFullWindowBoundingBox();
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
animationsDisabled = animationsDisabled || PWINDOW->m_sAdditionalConfigData.forceNoAnims;
} else if (PWORKSPACE) { } else if (PWORKSPACE) {
PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y}; WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y};
@@ -76,12 +76,12 @@ void CAnimationManager::tick() {
case AVARTYPE_FLOAT: { case AVARTYPE_FLOAT: {
// for disabled anims just warp // for disabled anims just warp
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) { if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp(); av->warp(false);
break; break;
} }
if (SPENT >= 1.f) { if (SPENT >= 1.f) {
av->warp(); av->warp(false);
break; break;
} }
@@ -97,12 +97,12 @@ void CAnimationManager::tick() {
case AVARTYPE_VECTOR: { case AVARTYPE_VECTOR: {
// for disabled anims just warp // for disabled anims just warp
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) { if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp(); av->warp(false);
break; break;
} }
if (SPENT >= 1.f) { if (SPENT >= 1.f) {
av->warp(); av->warp(false);
break; break;
} }
@@ -118,12 +118,12 @@ void CAnimationManager::tick() {
case AVARTYPE_COLOR: { case AVARTYPE_COLOR: {
// for disabled anims just warp // for disabled anims just warp
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) { if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp(); av->warp(false);
break; break;
} }
if (SPENT >= 1.f) { if (SPENT >= 1.f) {
av->warp(); av->warp(false);
break; break;
} }
@@ -151,7 +151,7 @@ void CAnimationManager::tick() {
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
} else if (PWORKSPACE) { } else if (PWORKSPACE) {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_bHidden) if (!w->m_bIsMapped || w->isHidden())
continue; continue;
if (w->m_iWorkspaceID != PWORKSPACE->m_iID) if (w->m_iWorkspaceID != PWORKSPACE->m_iID)
@@ -164,8 +164,7 @@ void CAnimationManager::tick() {
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR);
} }
break; break;
} } case AVARDAMAGE_BORDER: {
case AVARDAMAGE_BORDER: {
RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!"); RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!");
// damage only the border. // damage only the border.
@@ -223,13 +222,21 @@ void CAnimationManager::tick() {
} }
} }
// set size and pos if valid, but only if damage policy entire (dont if border for example) // set size and pos if valid, but only if damage policy entire (dont if border for example)
if (g_pCompositor->windowValidMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && PWINDOW->m_iX11Type != 2) if (g_pCompositor->windowValidMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && PWINDOW->m_iX11Type != 2)
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
// manually schedule a frame // manually schedule a frame
g_pCompositor->scheduleFrameForMonitor(PMONITOR); g_pCompositor->scheduleFrameForMonitor(PMONITOR);
// check if we did not finish animating. If so, trigger onAnimationEnd.
if (!av->isBeingAnimated())
animationEndedVars.push_back(av);
}
// do it here, because if this alters the animation vars deque we would be in trouble above.
for (auto& ave : animationEndedVars) {
ave->onAnimationEnd();
} }
} }
@@ -285,7 +292,7 @@ void CAnimationManager::animationPopin(CWindow* pWindow, bool close, float minPe
} }
void CAnimationManager::animationSlide(CWindow* pWindow, std::string force, bool close) { void CAnimationManager::animationSlide(CWindow* pWindow, std::string force, bool close) {
pWindow->m_vRealSize.warp(); // size we preserve in slide pWindow->m_vRealSize.warp(false); // size we preserve in slide
const auto GOALPOS = pWindow->m_vRealPosition.goalv(); const auto GOALPOS = pWindow->m_vRealPosition.goalv();
const auto GOALSIZE = pWindow->m_vRealSize.goalv(); const auto GOALSIZE = pWindow->m_vRealSize.goalv();
@@ -359,6 +366,10 @@ void CAnimationManager::onWindowPostCreateClose(CWindow* pWindow, bool close) {
if (!pWindow->m_vRealPosition.isBeingAnimated() && !pWindow->m_vRealSize.isBeingAnimated()) if (!pWindow->m_vRealPosition.isBeingAnimated() && !pWindow->m_vRealSize.isBeingAnimated())
return; return;
// if the animation is disabled and we are leaving, ignore the anim to prevent the snapshot being fucked
if (!pWindow->m_vRealPosition.m_pConfig->pValues->internalEnabled)
return;
if (pWindow->m_sAdditionalConfigData.animationStyle != "") { if (pWindow->m_sAdditionalConfigData.animationStyle != "") {
// the window has config'd special anim // the window has config'd special anim
if (pWindow->m_sAdditionalConfigData.animationStyle.find("slide") == 0) { if (pWindow->m_sAdditionalConfigData.animationStyle.find("slide") == 0) {

View File

@@ -18,6 +18,23 @@
CEventManager::CEventManager() { CEventManager::CEventManager() {
} }
int fdHandleWrite(int fd, uint32_t mask, void* data) {
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) {
// remove, hanged up
const auto ACCEPTEDFDS = (std::deque<std::pair<int, wl_event_source*>>*)data;
for (auto it = ACCEPTEDFDS->begin(); it != ACCEPTEDFDS->end(); ) {
if (it->first == fd) {
wl_event_source_remove(it->second); // remove this fd listener
it = ACCEPTEDFDS->erase(it);
} else {
it++;
}
}
}
return 0;
}
void CEventManager::startThread() { void CEventManager::startThread() {
m_tThread = std::thread([&]() { m_tThread = std::thread([&]() {
const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0); const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -46,15 +63,15 @@ void CEventManager::startThread() {
if (ACCEPTEDCONNECTION > 0) { if (ACCEPTEDCONNECTION > 0) {
// new connection! // new connection!
m_dAcceptedSocketFDs.push_back(ACCEPTEDCONNECTION);
int flagsNew = fcntl(ACCEPTEDCONNECTION, F_GETFL, 0); int flagsNew = fcntl(ACCEPTEDCONNECTION, F_GETFL, 0);
fcntl(ACCEPTEDCONNECTION, F_SETFL, flagsNew | O_NONBLOCK); fcntl(ACCEPTEDCONNECTION, F_SETFL, flagsNew | O_NONBLOCK);
Debug::log(LOG, "Socket 2 accepted a new client at FD %d", ACCEPTEDCONNECTION); Debug::log(LOG, "Socket 2 accepted a new client at FD %d", ACCEPTEDCONNECTION);
}
ensureFDsValid(); // add to event loop so we can close it when we need to
m_dAcceptedSocketFDs.push_back({ACCEPTEDCONNECTION, wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, WL_EVENT_READABLE, fdHandleWrite, &m_dAcceptedSocketFDs)});
}
} }
close(SOCKET); close(SOCKET);
@@ -63,34 +80,13 @@ void CEventManager::startThread() {
m_tThread.detach(); m_tThread.detach();
} }
void CEventManager::ensureFDsValid() {
static char readBuf[1024] = {0};
// pong if all FDs valid
for (auto it = m_dAcceptedSocketFDs.begin(); it != m_dAcceptedSocketFDs.end();) {
auto sizeRead = recv(*it, &readBuf, 1024, 0);
if (sizeRead != 0) {
it++;
continue;
}
// invalid!
Debug::log(LOG, "Removed invalid socket (2) FD: %d", *it);
it = m_dAcceptedSocketFDs.erase(it);
}
}
void CEventManager::flushEvents() { void CEventManager::flushEvents() {
ensureFDsValid();
eventQueueMutex.lock(); eventQueueMutex.lock();
for (auto& ev : m_dQueuedEvents) { for (auto& ev : m_dQueuedEvents) {
std::string eventString = (ev.event + ">>" + ev.data).substr(0, 1022) + "\n"; std::string eventString = (ev.event + ">>" + ev.data).substr(0, 1022) + "\n";
for (auto& fd : m_dAcceptedSocketFDs) { for (auto& fd : m_dAcceptedSocketFDs) {
write(fd, eventString.c_str(), eventString.length()); write(fd.first, eventString.c_str(), eventString.length());
} }
} }

View File

@@ -26,12 +26,11 @@ public:
private: private:
void flushEvents(); void flushEvents();
void ensureFDsValid();
std::mutex eventQueueMutex; std::mutex eventQueueMutex;
std::deque<SHyprIPCEvent> m_dQueuedEvents; std::deque<SHyprIPCEvent> m_dQueuedEvents;
std::deque<int> m_dAcceptedSocketFDs; std::deque<std::pair<int, wl_event_source*>> m_dAcceptedSocketFDs;
}; };
inline std::unique_ptr<CEventManager> g_pEventManager; inline std::unique_ptr<CEventManager> g_pEventManager;

View File

@@ -16,6 +16,7 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["pseudo"] = toggleActivePseudo; m_mDispatchers["pseudo"] = toggleActivePseudo;
m_mDispatchers["movefocus"] = moveFocusTo; m_mDispatchers["movefocus"] = moveFocusTo;
m_mDispatchers["movewindow"] = moveActiveTo; m_mDispatchers["movewindow"] = moveActiveTo;
m_mDispatchers["centerwindow"] = centerWindow;
m_mDispatchers["togglegroup"] = toggleGroup; m_mDispatchers["togglegroup"] = toggleGroup;
m_mDispatchers["changegroupactive"] = changeGroupActive; m_mDispatchers["changegroupactive"] = changeGroupActive;
m_mDispatchers["togglesplit"] = toggleSplit; m_mDispatchers["togglesplit"] = toggleSplit;
@@ -44,6 +45,7 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["swapactiveworkspaces"] = swapActiveWorkspaces; m_mDispatchers["swapactiveworkspaces"] = swapActiveWorkspaces;
m_mDispatchers["pin"] = pinActive; m_mDispatchers["pin"] = pinActive;
m_mDispatchers["mouse"] = mouse; m_mDispatchers["mouse"] = mouse;
m_mDispatchers["bringactivetotop"] = bringActiveToTop;
m_tScrollTimer.reset(); m_tScrollTimer.reset();
} }
@@ -163,7 +165,7 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
return true; return true;
} }
if (pKeyboard->isVirtual) if (pKeyboard->isVirtual && g_pInputManager->shouldIgnoreVirtualKeyboard(pKeyboard))
return true; return true;
if (!m_pXKBTranslationState) { if (!m_pXKBTranslationState) {
@@ -202,9 +204,9 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
m_dPressedKeycodes.push_back(KEYCODE); m_dPressedKeycodes.push_back(KEYCODE);
m_dPressedKeysyms.push_back(keysym); m_dPressedKeysyms.push_back(keysym);
found = g_pKeybindManager->handleKeybinds(MODS, "", keysym, 0, true, e->time_msec) || found; found = handleKeybinds(MODS, "", keysym, 0, true, e->time_msec) || found;
found = g_pKeybindManager->handleKeybinds(MODS, "", 0, KEYCODE, true, e->time_msec) || found; found = handleKeybinds(MODS, "", 0, KEYCODE, true, e->time_msec) || found;
if (found) if (found)
shadowKeybinds(keysym, KEYCODE); shadowKeybinds(keysym, KEYCODE);
@@ -219,9 +221,9 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
m_dPressedKeycodes.erase(std::remove(m_dPressedKeycodes.begin(), m_dPressedKeycodes.end(), KEYCODE), m_dPressedKeycodes.end()); m_dPressedKeycodes.erase(std::remove(m_dPressedKeycodes.begin(), m_dPressedKeycodes.end(), KEYCODE), m_dPressedKeycodes.end());
m_dPressedKeysyms.erase(std::remove(m_dPressedKeysyms.begin(), m_dPressedKeysyms.end(), keysym), m_dPressedKeysyms.end()); m_dPressedKeysyms.erase(std::remove(m_dPressedKeysyms.begin(), m_dPressedKeysyms.end(), keysym), m_dPressedKeysyms.end());
found = g_pKeybindManager->handleKeybinds(MODS, "", keysym, 0, false, e->time_msec) || found; found = handleKeybinds(MODS, "", keysym, 0, false, e->time_msec) || found;
found = g_pKeybindManager->handleKeybinds(MODS, "", 0, KEYCODE, false, e->time_msec) || found; found = handleKeybinds(MODS, "", 0, KEYCODE, false, e->time_msec) || found;
shadowKeybinds(); shadowKeybinds();
} }
@@ -244,9 +246,9 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
bool found = false; bool found = false;
if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_VERTICAL) { if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_VERTICAL) {
if (e->delta < 0) { if (e->delta < 0) {
found = g_pKeybindManager->handleKeybinds(MODS, "mouse_down", 0, 0, true, 0); found = handleKeybinds(MODS, "mouse_down", 0, 0, true, 0);
} else { } else {
found = g_pKeybindManager->handleKeybinds(MODS, "mouse_up", 0, 0, true, 0); found = handleKeybinds(MODS, "mouse_up", 0, 0, true, 0);
} }
if (found) if (found)
@@ -268,12 +270,12 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
bool mouseBindWasActive = ensureMouseBindState(); bool mouseBindWasActive = ensureMouseBindState();
if (e->state == WLR_BUTTON_PRESSED) { if (e->state == WLR_BUTTON_PRESSED) {
found = g_pKeybindManager->handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, true, 0); found = handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, true, 0);
if (found) if (found)
shadowKeybinds(); shadowKeybinds();
} else { } else {
found = g_pKeybindManager->handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, false, 0); found = handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, false, 0);
shadowKeybinds(); shadowKeybinds();
} }
@@ -281,6 +283,10 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
return !found && !mouseBindWasActive; return !found && !mouseBindWasActive;
} }
void CKeybindManager::onSwitchEvent(const std::string& switchName) {
handleKeybinds(0, "switch:" + switchName, 0, 0, true, 0);
}
int repeatKeyHandler(void* data) { int repeatKeyHandler(void* data) {
SKeybind** ppActiveKeybind = (SKeybind**)data; SKeybind** ppActiveKeybind = (SKeybind**)data;
@@ -419,10 +425,29 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
if (!(keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12)) if (!(keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12))
return false; return false;
const auto PSESSION = wlr_backend_get_session(g_pCompositor->m_sWLRBackend); // beyond this point, return true to not handle anything else.
if (PSESSION) { // we'll avoid printing shit to active windows.
const int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
wlr_session_change_vt(PSESSION, TTY); if (g_pCompositor->m_sWLRSession) {
const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
// vtnr is bugged for some reason.
const std::string TTYSTR = execAndGet("head -n 1 /sys/devices/virtual/tty/tty0/active").substr(3);
unsigned int ttynum = 0;
try {
ttynum = std::stoll(TTYSTR);
} catch (std::exception &e) {
; // oops?
}
if (ttynum == TTY)
return true;
Debug::log(LOG, "Switching from VT %i to VT %i", ttynum, TTY);
if (!wlr_session_change_vt(g_pCompositor->m_sWLRSession, TTY))
return true; // probably same session
g_pCompositor->m_bSessionActive = false; g_pCompositor->m_bSessionActive = false;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
@@ -435,7 +460,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
return true; return true;
} }
return false; return true;
} }
bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) {
@@ -458,6 +483,17 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) {
// Dispatchers // Dispatchers
void CKeybindManager::spawn(std::string args) { void CKeybindManager::spawn(std::string args) {
args = removeBeginEndSpacesTabs(args);
std::string RULES = "";
if (args[0] == '[') {
// we have exec rules
RULES = args.substr(1, args.substr(1).find_first_of(']'));
args = args.substr(args.find_first_of(']') + 1);
}
if (g_pXWaylandManager->m_sWLRXWayland) if (g_pXWaylandManager->m_sWLRXWayland)
args = "WAYLAND_DISPLAY=" + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + args; args = "WAYLAND_DISPLAY=" + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + args;
else else
@@ -480,6 +516,11 @@ void CKeybindManager::spawn(std::string args) {
} }
if (child == 0) { if (child == 0) {
// run in child // run in child
sigset_t set;
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);
grandchild = fork(); grandchild = fork();
if (grandchild == 0) { if (grandchild == 0) {
// run in grandchild // run in grandchild
@@ -505,7 +546,18 @@ void CKeybindManager::spawn(std::string args) {
Debug::log(LOG, "Fail to create the second fork"); Debug::log(LOG, "Fail to create the second fork");
return; return;
} }
Debug::log(LOG, "Process Created with pid %d", grandchild); Debug::log(LOG, "Process Created with pid %d", grandchild);
if (!RULES.empty()) {
const auto RULESLIST = CVarList(RULES, 0, ';');
for (auto& r : RULESLIST) {
g_pConfigManager->addExecRule({r, (unsigned long)grandchild});
}
Debug::log(LOG, "Applied %i rule arguments for exec.", RULESLIST.size());
}
} }
void CKeybindManager::killActive(std::string args) { void CKeybindManager::killActive(std::string args) {
@@ -539,23 +591,35 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
if (!PWINDOW) if (!PWINDOW)
return; return;
if (g_pCompositor->windowValidMapped(PWINDOW)) { // remove drag status
// remove drag status g_pInputManager->currentlyDraggedWindow = nullptr;
g_pInputManager->currentlyDraggedWindow = nullptr;
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID))
return; return;
PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating; PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating;
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW); PWINDOW->updateDynamicRules();
}
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW);
}
void CKeybindManager::centerWindow(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
PWINDOW->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.f - PWINDOW->m_vRealSize.goalv() / 2.f;
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
} }
void CKeybindManager::toggleActivePseudo(std::string args) { void CKeybindManager::toggleActivePseudo(std::string args) {
const auto ACTIVEWINDOW = g_pCompositor->m_pLastWindow; const auto ACTIVEWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(ACTIVEWINDOW)) if (!ACTIVEWINDOW)
return; return;
ACTIVEWINDOW->m_bIsPseudotiled = !ACTIVEWINDOW->m_bIsPseudotiled; ACTIVEWINDOW->m_bIsPseudotiled = !ACTIVEWINDOW->m_bIsPseudotiled;
@@ -582,16 +646,20 @@ void CKeybindManager::changeworkspace(std::string args) {
internal = true; internal = true;
} else if (args.find("previous") == 0) { } else if (args.find("previous") == 0) {
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID( const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
g_pCompositor->m_pLastMonitor->activeWorkspace);
// Do nothing if there's no previous workspace, otherwise switch to it. // Do nothing if there's no previous workspace, otherwise switch to it.
if (PCURRENTWORKSPACE->m_iPrevWorkspaceID == -1) { if (PCURRENTWORKSPACE->m_iPrevWorkspaceID == -1) {
Debug::log(LOG, "No previous workspace to change to"); Debug::log(LOG, "No previous workspace to change to");
return; return;
} } else {
else {
workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID; workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID;
if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(workspaceToChangeTo); PWORKSPACETOCHANGETO)
workspaceName = PWORKSPACETOCHANGETO->m_szName;
else
workspaceName = std::to_string(workspaceToChangeTo);
isSwitchingToPrevious = true; isSwitchingToPrevious = true;
// If the previous workspace ID isn't reset, cycles can form when continually going // If the previous workspace ID isn't reset, cycles can form when continually going
@@ -614,23 +682,33 @@ void CKeybindManager::changeworkspace(std::string args) {
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
static auto *const PBACKANDFORTH = &g_pConfigManager->getConfigValuePtr("binds:workspace_back_and_forth")->intValue; static auto *const PBACKANDFORTH = &g_pConfigManager->getConfigValuePtr("binds:workspace_back_and_forth")->intValue;
if (*PBACKANDFORTH && PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && PCURRENTWORKSPACE->m_iPrevWorkspaceID != -1 && !internal) { if (*PBACKANDFORTH && PCURRENTWORKSPACE && PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && PCURRENTWORKSPACE->m_iPrevWorkspaceID != -1 && !internal) {
const auto PPREVWORKSPACE = g_pCompositor->getWorkspaceByID(PCURRENTWORKSPACE->m_iPrevWorkspaceID);
workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID; workspaceToChangeTo = PCURRENTWORKSPACE->m_iPrevWorkspaceID;
if (PPREVWORKSPACE)
workspaceName = PPREVWORKSPACE->m_szName;
else
workspaceName = std::to_string(workspaceToChangeTo);
isSwitchingToPrevious = true; isSwitchingToPrevious = true;
// If the previous workspace ID isn't reset, cycles can form when continually going // If the previous workspace ID isn't reset, cycles can form when continually going
// to the previous workspace again and again. // to the previous workspace again and again.
static auto *const PALLOWWORKSPACECYCLES = &g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles")->intValue; static auto* const PALLOWWORKSPACECYCLES = &g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles")->intValue;
if (!*PALLOWWORKSPACECYCLES) if (!*PALLOWWORKSPACECYCLES)
PCURRENTWORKSPACE->m_iPrevWorkspaceID = -1; PCURRENTWORKSPACE->m_iPrevWorkspaceID = -1;
} else if (PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && !internal) } else if (PCURRENTWORKSPACE && PCURRENTWORKSPACE->m_iID == workspaceToChangeTo && !internal)
return; return;
// remove constraints // remove constraints
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
g_pInputManager->m_bEmptyFocusCursorSet = false;
// if it's not internal, we will unfocus to prevent stuck focus // if it's not internal, we will unfocus to prevent stuck focus
if (!internal) if (!internal)
g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(nullptr);
@@ -645,7 +723,7 @@ void CKeybindManager::changeworkspace(std::string args) {
// Remember previous workspace. // Remember previous workspace.
PWORKSPACETOCHANGETO->m_iPrevWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace; PWORKSPACETOCHANGETO->m_iPrevWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
if (workspaceToChangeTo == SPECIAL_WORKSPACE_ID) if (g_pCompositor->isWorkspaceSpecial(workspaceToChangeTo))
PWORKSPACETOCHANGETO->m_iMonitorID = PMONITOR->ID; PWORKSPACETOCHANGETO->m_iMonitorID = PMONITOR->ID;
// if it's not visible, make it visible. // if it's not visible, make it visible.
@@ -660,10 +738,10 @@ void CKeybindManager::changeworkspace(std::string args) {
} }
// change it // change it
if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID) if (!g_pCompositor->isWorkspaceSpecial(workspaceToChangeTo))
PMONITOR->activeWorkspace = workspaceToChangeTo; PMONITOR->activeWorkspace = workspaceToChangeTo;
else else
PMONITOR->specialWorkspaceOpen = true; PMONITOR->specialWorkspaceID = workspaceToChangeTo;
// here and only here begin anim. we don't want to anim visible workspaces on other monitors. // here and only here begin anim. we don't want to anim visible workspaces on other monitors.
// check if anim left or right // check if anim left or right
@@ -679,11 +757,9 @@ void CKeybindManager::changeworkspace(std::string args) {
} }
// If the monitor is not the one our cursor's at, warp to it. // If the monitor is not the one our cursor's at, warp to it.
const bool anotherMonitor = PMONITOR != g_pCompositor->getMonitorFromCursor(); const bool anotherMonitor = PMONITOR != g_pCompositor->m_pLastMonitor;
if (anotherMonitor) { if (anotherMonitor)
Vector2D middle = PMONITOR->vecPosition + PMONITOR->vecSize / 2.f; g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f);
g_pCompositor->warpCursorTo(middle);
}
// set active and deactivate all other in wlr // set active and deactivate all other in wlr
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACETOCHANGETO->m_pWlrHandle); g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACETOCHANGETO->m_pWlrHandle);
@@ -708,7 +784,7 @@ void CKeybindManager::changeworkspace(std::string args) {
g_pInputManager->refocus(); g_pInputManager->refocus();
// set the new monitor as the last (no warps would bug otherwise) // set the new monitor as the last (no warps would bug otherwise)
g_pCompositor->m_pLastMonitor = g_pCompositor->getMonitorFromID(PWORKSPACETOCHANGETO->m_iMonitorID); g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromID(PWORKSPACETOCHANGETO->m_iMonitorID));
// mark the monitor dirty // mark the monitor dirty
g_pHyprRenderer->damageMonitor(PMONITOR); g_pHyprRenderer->damageMonitor(PMONITOR);
@@ -730,7 +806,9 @@ void CKeybindManager::changeworkspace(std::string args) {
if (const auto POLDWORKSPACE = g_pCompositor->getWorkspaceByID(OLDWORKSPACE); POLDWORKSPACE) if (const auto POLDWORKSPACE = g_pCompositor->getWorkspaceByID(OLDWORKSPACE); POLDWORKSPACE)
POLDWORKSPACE->startAnim(false, ANIMTOLEFT); POLDWORKSPACE->startAnim(false, ANIMTOLEFT);
const auto PWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(PMONITOR->ID, workspaceName, workspaceToChangeTo == SPECIAL_WORKSPACE_ID)).get(); const auto PWORKSPACE = g_pCompositor->createNewWorkspace(workspaceToChangeTo, PMONITOR->ID, workspaceName);
const bool ANOTHERMONITOR = PMONITOR != g_pCompositor->m_pLastMonitor;
if (!isSwitchingToPrevious) if (!isSwitchingToPrevious)
// Remember previous workspace. // Remember previous workspace.
@@ -739,14 +817,7 @@ void CKeybindManager::changeworkspace(std::string args) {
// start anim on new workspace // start anim on new workspace
PWORKSPACE->startAnim(true, ANIMTOLEFT); PWORKSPACE->startAnim(true, ANIMTOLEFT);
// We are required to set the name here immediately PMONITOR->specialWorkspaceID = 0;
if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID)
wlr_ext_workspace_handle_v1_set_name(PWORKSPACE->m_pWlrHandle, workspaceName.c_str());
PWORKSPACE->m_iID = workspaceToChangeTo;
PWORKSPACE->m_iMonitorID = PMONITOR->ID;
PMONITOR->specialWorkspaceOpen = false;
// fix pinned windows // fix pinned windows
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
@@ -755,10 +826,10 @@ void CKeybindManager::changeworkspace(std::string args) {
} }
} }
if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID) if (!g_pCompositor->isWorkspaceSpecial(workspaceToChangeTo))
PMONITOR->activeWorkspace = workspaceToChangeTo; PMONITOR->activeWorkspace = workspaceToChangeTo;
else else
PMONITOR->specialWorkspaceOpen = true; PMONITOR->specialWorkspaceID = workspaceToChangeTo;
// set active and deactivate all other // set active and deactivate all other
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACE->m_pWlrHandle); g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACE->m_pWlrHandle);
@@ -771,13 +842,16 @@ void CKeybindManager::changeworkspace(std::string args) {
if (g_pCompositor->m_pLastMonitor != PMONITOR) if (g_pCompositor->m_pLastMonitor != PMONITOR)
g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f); g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f);
g_pCompositor->m_pLastMonitor = PMONITOR; g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PWORKSPACE->m_szName});
g_pCompositor->setActiveMonitor(PMONITOR);
// focus (clears the last) // focus (clears the last)
g_pInputManager->refocus(); g_pInputManager->refocus();
// Event // Events
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PWORKSPACE->m_szName}); if (ANOTHERMONITOR)
g_pCompositor->warpCursorTo(PMONITOR->vecPosition + PMONITOR->vecSize / 2.f);
Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo); Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo);
} }
@@ -785,10 +859,10 @@ void CKeybindManager::changeworkspace(std::string args) {
void CKeybindManager::fullscreenActive(std::string args) { void CKeybindManager::fullscreenActive(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!PWINDOW)
return; return;
if (PWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID))
return; return;
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL);
@@ -805,14 +879,14 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
PWINDOW = g_pCompositor->m_pLastWindow; PWINDOW = g_pCompositor->m_pLastWindow;
} }
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!PWINDOW)
return; return;
const auto OLDWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); const auto OLDWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
// hack // hack
std::string unusedName; std::string workspaceName;
const auto WORKSPACEID = getWorkspaceIDFromString(args, unusedName); const auto WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
if (WORKSPACEID == PWINDOW->m_iWorkspaceID) { if (WORKSPACEID == PWINDOW->m_iWorkspaceID) {
Debug::log(LOG, "Not moving to workspace because it didn't change."); Debug::log(LOG, "Not moving to workspace because it didn't change.");
@@ -821,12 +895,11 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
auto PSAVEDSIZE = PWINDOW->m_vRealSize.goalv(); auto PSAVEDSIZE = PWINDOW->m_vRealSize.goalv();
auto PSAVEDPOS = PWINDOW->m_vRealPosition.goalv(); auto PSAVEDPOS = PWINDOW->m_vRealPosition.goalv();
const bool WASFULLSCREEN = PWINDOW->m_bIsFullscreen;
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
g_pKeybindManager->changeworkspace(args); auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
if (PWORKSPACE == OLDWORKSPACE) { if (PWORKSPACE == OLDWORKSPACE) {
Debug::log(LOG, "Not moving to workspace because it didn't change."); Debug::log(LOG, "Not moving to workspace because it didn't change.");
@@ -834,19 +907,13 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
} }
if (!PWORKSPACE) { if (!PWORKSPACE) {
Debug::log(ERR, "Workspace null in moveActiveToWorkspace?"); // create
return; PWORKSPACE = g_pCompositor->createNewWorkspace(WORKSPACEID, OLDWORKSPACE->m_iMonitorID, workspaceName);
} }
OLDWORKSPACE->m_bHasFullscreenWindow = false;
PWINDOW->moveToWorkspace(PWORKSPACE->m_iID); PWINDOW->moveToWorkspace(PWORKSPACE->m_iID);
PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID; PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID;
if (PWINDOW->m_bIsFullscreen) {
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
}
if (PWORKSPACE->m_bHasFullscreenWindow) { if (PWORKSPACE->m_bHasFullscreenWindow) {
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_FULL);
} }
@@ -858,22 +925,19 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
// and restore it // and restore it
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
PWINDOW->m_vRealSize.setValue(PSAVEDSIZE); PWINDOW->m_vRealSize.setValueAndWarp(PSAVEDSIZE);
PWINDOW->m_vRealPosition.setValueAndWarp(PSAVEDPOS - g_pCompositor->getMonitorFromID(OLDWORKSPACE->m_iMonitorID)->vecPosition + g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID)->vecPosition); 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(); PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
} }
// undo the damage if we are moving to the special workspace if (WASFULLSCREEN)
if (WORKSPACEID == SPECIAL_WORKSPACE_ID) { g_pCompositor->setWindowFullscreen(PWINDOW, true, OLDWORKSPACE->m_efFullscreenMode);
changeworkspace("[internal]" + std::to_string(OLDWORKSPACE->m_iID));
OLDWORKSPACE->startAnim(true, true, true);
toggleSpecialWorkspace("");
g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false, true);
for (auto& m : g_pCompositor->m_vMonitors) if (!g_pCompositor->isWorkspaceSpecial(WORKSPACEID)) {
m->specialWorkspaceOpen = false; g_pKeybindManager->changeworkspace(args);
} else {
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
} else {
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
} }
PWINDOW->updateToplevel(); PWINDOW->updateToplevel();
@@ -881,6 +945,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
// hacky, but works lol // hacky, but works lol
// TODO: this sucks
CWindow* PWINDOW = nullptr; CWindow* PWINDOW = nullptr;
@@ -893,7 +958,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
PWINDOW = g_pCompositor->m_pLastWindow; PWINDOW = g_pCompositor->m_pLastWindow;
} }
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!PWINDOW)
return; return;
int workspaceToMoveTo = 0; int workspaceToMoveTo = 0;
@@ -951,7 +1016,11 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
// manually post event cuz it got ignored above // manually post event cuz it got ignored above
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%x,%s", PWINDOW, PWORKSPACE->m_szName.c_str())}); g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%x,%s", PWINDOW, PWORKSPACE->m_szName.c_str())});
g_pInputManager->refocus(); PWINDOW->m_iWorkspaceID = OLDWORKSPACEIDRETURN;
const auto PNEXTCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW);
PWINDOW->m_iWorkspaceID = workspaceToMoveTo;
g_pCompositor->focusWindow(PNEXTCANDIDATE);
} }
void CKeybindManager::moveFocusTo(std::string args) { void CKeybindManager::moveFocusTo(std::string args) {
@@ -988,27 +1057,15 @@ void CKeybindManager::moveFocusTo(std::string args) {
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f; Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f;
g_pCompositor->warpCursorTo(middle); g_pCompositor->warpCursorTo(middle);
if (PWINDOWTOCHANGETO->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) { if (PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) {
// event // event
const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID); const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID);
const auto PNEWWS = g_pCompositor->getWorkspaceByID(PNEWMON->activeWorkspace);
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PNEWMON->szName + "," + PNEWWS->m_szName});
g_pCompositor->m_pLastMonitor = PNEWMON; g_pCompositor->setActiveMonitor(PNEWMON);
} }
} }
}; };
if (!g_pCompositor->windowValidMapped(PLASTWINDOW)) {
const auto PWINDOWTOCHANGETO = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace);
if (!PWINDOWTOCHANGETO)
return;
switchToWindow(PWINDOWTOCHANGETO);
return;
}
const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
if (PWINDOWTOCHANGETO) { if (PWINDOWTOCHANGETO) {
@@ -1053,12 +1110,12 @@ void CKeybindManager::moveActiveTo(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PLASTWINDOW) || PLASTWINDOW->m_bIsFullscreen) if (!PLASTWINDOW || PLASTWINDOW->m_bIsFullscreen)
return; return;
const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
if (!g_pCompositor->windowValidMapped(PWINDOWTOCHANGETO)) if (!PWINDOWTOCHANGETO)
return; return;
g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, PWINDOWTOCHANGETO); g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, PWINDOWTOCHANGETO);
@@ -1104,7 +1161,7 @@ void CKeybindManager::alterSplitRatio(std::string args) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PLASTWINDOW)) if (!PLASTWINDOW)
return; return;
g_pLayoutManager->getCurrentLayout()->alterSplitRatioBy(PLASTWINDOW, splitratio); g_pLayoutManager->getCurrentLayout()->alterSplitRatioBy(PLASTWINDOW, splitratio);
@@ -1113,7 +1170,7 @@ void CKeybindManager::alterSplitRatio(std::string args) {
void CKeybindManager::focusMonitor(std::string arg) { void CKeybindManager::focusMonitor(std::string arg) {
const auto PMONITOR = g_pCompositor->getMonitorFromString(arg); const auto PMONITOR = g_pCompositor->getMonitorFromString(arg);
if (!PMONITOR) if (!PMONITOR || PMONITOR == g_pCompositor->m_pLastMonitor)
return; return;
changeworkspace("[internal]" + std::to_string(PMONITOR->activeWorkspace)); changeworkspace("[internal]" + std::to_string(PMONITOR->activeWorkspace));
@@ -1134,7 +1191,7 @@ void CKeybindManager::moveCursorToCorner(std::string arg) {
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!PWINDOW)
return; return;
switch (CORNER) { switch (CORNER) {
@@ -1266,52 +1323,93 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
void CKeybindManager::toggleSpecialWorkspace(std::string args) { void CKeybindManager::toggleSpecialWorkspace(std::string args) {
if (g_pCompositor->getWindowsOnWorkspace(SPECIAL_WORKSPACE_ID) == 0) { static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
std::string workspaceName = "";
int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName);
if (workspaceID == INT_MAX || !g_pCompositor->isWorkspaceSpecial(workspaceID)) {
Debug::log(ERR, "Invalid workspace passed to special");
return;
}
if (g_pCompositor->getWindowsOnWorkspace(workspaceID) == 0) {
Debug::log(LOG, "Can't open empty special workspace!"); Debug::log(LOG, "Can't open empty special workspace!");
return; return;
} }
bool open = false; bool requestedWorkspaceIsAlreadyOpen = false;
const auto PMONITOR = *PFOLLOWMOUSE == 1 ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->m_pLastMonitor;
int specialOpenOnMonitor = PMONITOR->specialWorkspaceID;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (m->specialWorkspaceOpen) { if (m->specialWorkspaceID == workspaceID) {
open = true; requestedWorkspaceIsAlreadyOpen = true;
break; break;
} }
} }
if (open) if (requestedWorkspaceIsAlreadyOpen && specialOpenOnMonitor == workspaceID)
Debug::log(LOG, "Toggling special workspace to closed"); Debug::log(LOG, "Toggling special workspace %d to closed");
else else
Debug::log(LOG, "Toggling special workspace to open"); Debug::log(LOG, "Toggling special workspace %d to open");
if (open) { if (requestedWorkspaceIsAlreadyOpen && specialOpenOnMonitor == workspaceID) {
for (auto& m : g_pCompositor->m_vMonitors) { // already open on this monitor
if (m->specialWorkspaceOpen != !open) {
m->specialWorkspaceOpen = !open;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false); PMONITOR->specialWorkspaceID = 0;
} g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
g_pCompositor->getWorkspaceByID(workspaceID)->startAnim(false, false);
if (const auto PWINDOW = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace)->getLastFocusedWindow(); PWINDOW)
g_pCompositor->focusWindow(PWINDOW);
else
g_pInputManager->refocus();
} else if (requestedWorkspaceIsAlreadyOpen) {
// already open on another monitor
if (specialOpenOnMonitor) {
g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID)->startAnim(false, false);
PMONITOR->specialWorkspaceID = 0;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
} }
if (const auto PWINDOW = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace)->getLastFocusedWindow(); PWINDOW) // move to current
const auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceID);
const auto POLDMON = g_pCompositor->getMonitorFromID(PSPECIALWORKSPACE->m_iMonitorID);
POLDMON->specialWorkspaceID = 0;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
PMONITOR->specialWorkspaceID = workspaceID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
PSPECIALWORKSPACE->m_iMonitorID = PMONITOR->ID;
if (const auto PWINDOW = PSPECIALWORKSPACE->getLastFocusedWindow(); PWINDOW)
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
else else
g_pInputManager->refocus(); g_pInputManager->refocus();
} else { } else {
auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID); // not open anywhere
if (specialOpenOnMonitor) {
g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID)->startAnim(false, false);
PMONITOR->specialWorkspaceID = 0;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
}
auto PSPECIALWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceID);
if (!PSPECIALWORKSPACE) { if (!PSPECIALWORKSPACE) {
// ??? happens sometimes...? // ??? happens sometimes...?
PSPECIALWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(g_pCompositor->m_pLastMonitor->ID, "special", true)).get(); PSPECIALWORKSPACE = g_pCompositor->createNewWorkspace(workspaceID, PMONITOR->ID, workspaceName);
} }
g_pCompositor->m_pLastMonitor->specialWorkspaceOpen = true; PMONITOR->specialWorkspaceID = workspaceID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(g_pCompositor->m_pLastMonitor->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
PSPECIALWORKSPACE->m_iMonitorID = PMONITOR->ID;
PSPECIALWORKSPACE->startAnim(true, true); PSPECIALWORKSPACE->startAnim(true, true);
PSPECIALWORKSPACE->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID;
if (const auto PWINDOW = PSPECIALWORKSPACE->getLastFocusedWindow(); PWINDOW) if (const auto PWINDOW = PSPECIALWORKSPACE->getLastFocusedWindow(); PWINDOW)
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
@@ -1324,7 +1422,7 @@ void CKeybindManager::forceRendererReload(std::string args) {
bool overAgain = false; bool overAgain = false;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
auto rule = g_pConfigManager->getMonitorRuleFor(m->szName); auto rule = g_pConfigManager->getMonitorRuleFor(m->szName, m->output->description ? m->output->description : "");
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) { if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) {
overAgain = true; overAgain = true;
break; break;
@@ -1336,7 +1434,7 @@ void CKeybindManager::forceRendererReload(std::string args) {
} }
void CKeybindManager::resizeActive(std::string args) { void CKeybindManager::resizeActive(std::string args) {
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) || g_pCompositor->m_pLastWindow->m_bIsFullscreen) if (!g_pCompositor->m_pLastWindow || g_pCompositor->m_pLastWindow->m_bIsFullscreen)
return; return;
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealSize.goalv()); const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealSize.goalv());
@@ -1344,11 +1442,11 @@ void CKeybindManager::resizeActive(std::string args) {
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - g_pCompositor->m_pLastWindow->m_vRealSize.goalv()); g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - g_pCompositor->m_pLastWindow->m_vRealSize.goalv());
if (g_pCompositor->m_pLastWindow->m_vRealSize.goalv().x > 1 && g_pCompositor->m_pLastWindow->m_vRealSize.goalv().y > 1) if (g_pCompositor->m_pLastWindow->m_vRealSize.goalv().x > 1 && g_pCompositor->m_pLastWindow->m_vRealSize.goalv().y > 1)
g_pCompositor->m_pLastWindow->m_bHidden = false; g_pCompositor->m_pLastWindow->setHidden(false);
} }
void CKeybindManager::moveActive(std::string args) { void CKeybindManager::moveActive(std::string args) {
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) || g_pCompositor->m_pLastWindow->m_bIsFullscreen) if (!g_pCompositor->m_pLastWindow || g_pCompositor->m_pLastWindow->m_bIsFullscreen)
return; return;
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealPosition.goalv()); const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealPosition.goalv());
@@ -1396,18 +1494,15 @@ void CKeybindManager::resizeWindow(std::string args) {
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize.goalv(), PWINDOW); g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize.goalv(), PWINDOW);
if (PWINDOW->m_vRealSize.goalv().x > 1 && PWINDOW->m_vRealSize.goalv().y > 1) if (PWINDOW->m_vRealSize.goalv().x > 1 && PWINDOW->m_vRealSize.goalv().y > 1)
PWINDOW->m_bHidden = false; PWINDOW->setHidden(false);
} }
void CKeybindManager::circleNext(std::string arg) { void CKeybindManager::circleNext(std::string arg) {
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return;
auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) { auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) {
if (PWINDOWTOCHANGETO == g_pCompositor->m_pLastWindow || !PWINDOWTOCHANGETO) if (PWINDOWTOCHANGETO == g_pCompositor->m_pLastWindow || !PWINDOWTOCHANGETO)
return; return;
if (g_pCompositor->m_pLastWindow->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsFullscreen) { if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsFullscreen) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID);
const auto FSMODE = PWORKSPACE->m_efFullscreenMode; const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
@@ -1425,6 +1520,17 @@ void CKeybindManager::circleNext(std::string arg) {
} }
}; };
if (!g_pCompositor->m_pLastWindow) {
// if we have a clear focus, find the first window and get the next focusable.
if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace) > 0) {
const auto PWINDOW = g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace), true);
switchToWindow(PWINDOW);
}
return;
}
if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") if (arg == "last" || arg == "l" || arg == "prev" || arg == "p")
switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow, true)); switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow, true));
else else
@@ -1551,20 +1657,32 @@ void CKeybindManager::layoutmsg(std::string msg) {
void CKeybindManager::toggleOpaque(std::string unused) { void CKeybindManager::toggleOpaque(std::string unused) {
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!PWINDOW)
return; return;
PWINDOW->m_sAdditionalConfigData.forceOpaque = !PWINDOW->m_sAdditionalConfigData.forceOpaque; PWINDOW->m_sAdditionalConfigData.forceOpaque = !PWINDOW->m_sAdditionalConfigData.forceOpaque;
PWINDOW->m_sAdditionalConfigData.forceOpaqueOverriden = true;
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
} }
void CKeybindManager::dpms(std::string arg) { void CKeybindManager::dpms(std::string arg) {
bool enable = arg == "on"; bool enable = arg.find("on") == 0;
std::string port = "";
if (arg.find_first_of(' ') != std::string::npos) {
port = arg.substr(arg.find_first_of(' ') + 1);
}
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (!port.empty() && m->szName != port)
continue;
wlr_output_enable(m->output, enable); wlr_output_enable(m->output, enable);
m->dpmsStatus = enable;
if (!wlr_output_commit(m->output)) { if (!wlr_output_commit(m->output)) {
Debug::log(ERR, "Couldn't commit output %s", m->szName.c_str()); Debug::log(ERR, "Couldn't commit output %s", m->szName.c_str());
} }
@@ -1580,7 +1698,7 @@ void CKeybindManager::swapnext(std::string arg) {
CWindow* toSwap = nullptr; CWindow* toSwap = nullptr;
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow)) if (!g_pCompositor->m_pLastWindow)
return; return;
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
@@ -1621,12 +1739,15 @@ void CKeybindManager::swapActiveWorkspaces(std::string args) {
} }
void CKeybindManager::pinActive(std::string args) { void CKeybindManager::pinActive(std::string args) {
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) || !g_pCompositor->m_pLastWindow->m_bIsFloating || g_pCompositor->m_pLastWindow->m_bIsFullscreen) if (!g_pCompositor->m_pLastWindow || !g_pCompositor->m_pLastWindow->m_bIsFloating || g_pCompositor->m_pLastWindow->m_bIsFullscreen)
return; return;
g_pCompositor->m_pLastWindow->m_bPinned = !g_pCompositor->m_pLastWindow->m_bPinned; g_pCompositor->m_pLastWindow->m_bPinned = !g_pCompositor->m_pLastWindow->m_bPinned;
g_pCompositor->m_pLastWindow->m_iWorkspaceID = g_pCompositor->getMonitorFromID(g_pCompositor->m_pLastWindow->m_iMonitorID)->activeWorkspace; g_pCompositor->m_pLastWindow->m_iWorkspaceID = g_pCompositor->getMonitorFromID(g_pCompositor->m_pLastWindow->m_iMonitorID)->activeWorkspace;
g_pCompositor->m_pLastWindow->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(g_pCompositor->m_pLastWindow);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastWindow->m_iWorkspaceID);
PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()); PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal());
@@ -1640,7 +1761,7 @@ void CKeybindManager::mouse(std::string args) {
if (PRESSED) { if (PRESSED) {
g_pKeybindManager->m_bIsMouseBindActive = true; g_pKeybindManager->m_bIsMouseBindActive = true;
g_pInputManager->currentlyDraggedWindow = g_pCompositor->windowFromCursor(); g_pInputManager->currentlyDraggedWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
g_pInputManager->dragMode = MBIND_MOVE; g_pInputManager->dragMode = MBIND_MOVE;
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
@@ -1657,7 +1778,7 @@ void CKeybindManager::mouse(std::string args) {
if (PRESSED) { if (PRESSED) {
g_pKeybindManager->m_bIsMouseBindActive = true; g_pKeybindManager->m_bIsMouseBindActive = true;
g_pInputManager->currentlyDraggedWindow = g_pCompositor->windowFromCursor(); g_pInputManager->currentlyDraggedWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
g_pInputManager->dragMode = MBIND_RESIZE; g_pInputManager->dragMode = MBIND_RESIZE;
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
@@ -1672,3 +1793,8 @@ void CKeybindManager::mouse(std::string args) {
} }
} }
} }
void CKeybindManager::bringActiveToTop(std::string args) {
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsFloating)
g_pCompositor->moveWindowToTop(g_pCompositor->m_pLastWindow);
}

View File

@@ -7,6 +7,7 @@
#include <functional> #include <functional>
class CInputManager; class CInputManager;
class CConfigManager;
struct SKeybind { struct SKeybind {
std::string key = ""; std::string key = "";
@@ -38,6 +39,7 @@ public:
bool onKeyEvent(wlr_keyboard_key_event*, SKeyboard*); bool onKeyEvent(wlr_keyboard_key_event*, SKeyboard*);
bool onAxisEvent(wlr_pointer_axis_event*); bool onAxisEvent(wlr_pointer_axis_event*);
bool onMouseEvent(wlr_pointer_button_event*); bool onMouseEvent(wlr_pointer_button_event*);
void onSwitchEvent(const std::string&);
void addKeybind(SKeybind); void addKeybind(SKeybind);
void removeKeybind(uint32_t, const std::string&); void removeKeybind(uint32_t, const std::string&);
@@ -91,6 +93,7 @@ private:
static void moveActiveToWorkspace(std::string); static void moveActiveToWorkspace(std::string);
static void moveActiveToWorkspaceSilent(std::string); static void moveActiveToWorkspaceSilent(std::string);
static void moveFocusTo(std::string); static void moveFocusTo(std::string);
static void centerWindow(std::string);
static void moveActiveTo(std::string); static void moveActiveTo(std::string);
static void toggleGroup(std::string); static void toggleGroup(std::string);
static void changeGroupActive(std::string); static void changeGroupActive(std::string);
@@ -119,9 +122,11 @@ private:
static void swapActiveWorkspaces(std::string); static void swapActiveWorkspaces(std::string);
static void pinActive(std::string); static void pinActive(std::string);
static void mouse(std::string); static void mouse(std::string);
static void bringActiveToTop(std::string);
friend class CCompositor; friend class CCompositor;
friend class CInputManager; friend class CInputManager;
friend class CConfigManager;
}; };
inline std::unique_ptr<CKeybindManager> g_pKeybindManager; inline std::unique_ptr<CKeybindManager> g_pKeybindManager;

View File

@@ -0,0 +1,5 @@
#include "ProtocolManager.hpp"
CProtocolManager::CProtocolManager() {
m_pToplevelExportProtocolManager = std::make_unique<CToplevelExportProtocolManager>();
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "../defines.hpp"
#include "../protocols/ToplevelExport.hpp"
class CProtocolManager {
public:
CProtocolManager();
std::unique_ptr<CToplevelExportProtocolManager> m_pToplevelExportProtocolManager;
};
inline std::unique_ptr<CProtocolManager> g_pProtocolManager;

View File

@@ -3,21 +3,23 @@
#include "../events/Events.hpp" #include "../events/Events.hpp"
CHyprXWaylandManager::CHyprXWaylandManager() { CHyprXWaylandManager::CHyprXWaylandManager() {
if (XWAYLAND) { #ifndef NO_XWAYLAND
m_sWLRXWayland = wlr_xwayland_create(g_pCompositor->m_sWLDisplay, g_pCompositor->m_sWLRCompositor, 1); m_sWLRXWayland = wlr_xwayland_create(g_pCompositor->m_sWLDisplay, g_pCompositor->m_sWLRCompositor, 1);
if (!m_sWLRXWayland) { if (!m_sWLRXWayland) {
Debug::log(ERR, "Couldn't start up the XWaylandManager because wlr_xwayland_create returned a nullptr!"); Debug::log(ERR, "Couldn't start up the XWaylandManager because wlr_xwayland_create returned a nullptr!");
return; return;
}
addWLSignal(&m_sWLRXWayland->events.ready, &Events::listen_readyXWayland, m_sWLRXWayland, "XWayland Manager");
addWLSignal(&m_sWLRXWayland->events.new_surface, &Events::listen_surfaceXWayland, m_sWLRXWayland, "XWayland Manager");
setenv("DISPLAY", m_sWLRXWayland->display_name, 1);
Debug::log(LOG, "CHyprXWaylandManager started on display %s", m_sWLRXWayland->display_name);
} }
addWLSignal(&m_sWLRXWayland->events.ready, &Events::listen_readyXWayland, m_sWLRXWayland, "XWayland Manager");
addWLSignal(&m_sWLRXWayland->events.new_surface, &Events::listen_surfaceXWayland, m_sWLRXWayland, "XWayland Manager");
setenv("DISPLAY", m_sWLRXWayland->display_name, 1);
Debug::log(LOG, "CHyprXWaylandManager started on display %s", m_sWLRXWayland->display_name);
#else
unsetenv("DISPLAY"); // unset DISPLAY so that X11 apps do not try to start on a different/invalid DISPLAY
#endif
} }
CHyprXWaylandManager::~CHyprXWaylandManager() { CHyprXWaylandManager::~CHyprXWaylandManager() {
@@ -51,17 +53,21 @@ void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate)
void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) { void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) {
if (pWindow->m_bIsX11) { if (pWindow->m_bIsX11) {
if (pWindow->m_uSurface.xwayland->minimized)
if (activate) {
wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false); wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false);
wlr_xwayland_surface_restack(pWindow->m_uSurface.xwayland, NULL, XCB_STACK_MODE_ABOVE);
}
wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate); wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate);
wlr_xwayland_surface_restack(pWindow->m_uSurface.xwayland, NULL, XCB_STACK_MODE_ABOVE);
} }
else else
wlr_xdg_toplevel_set_activated(pWindow->m_uSurface.xdg->toplevel, activate); wlr_xdg_toplevel_set_activated(pWindow->m_uSurface.xdg->toplevel, activate);
g_pCompositor->m_pLastFocus = getWindowSurface(pWindow); if (activate) {
g_pCompositor->m_pLastWindow = pWindow; g_pCompositor->m_pLastFocus = getWindowSurface(pWindow);
g_pCompositor->m_pLastWindow = pWindow;
}
if (!pWindow->m_bPinned) if (!pWindow->m_bPinned)
g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID)->m_pLastFocusedWindow = pWindow; g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID)->m_pLastFocusedWindow = pWindow;
@@ -69,10 +75,19 @@ void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) {
void CHyprXWaylandManager::getGeometryForWindow(CWindow* pWindow, wlr_box* pbox) { void CHyprXWaylandManager::getGeometryForWindow(CWindow* pWindow, wlr_box* pbox) {
if (pWindow->m_bIsX11) { if (pWindow->m_bIsX11) {
pbox->x = pWindow->m_uSurface.xwayland->x; const auto SIZEHINTS = pWindow->m_uSurface.xwayland->size_hints;
pbox->y = pWindow->m_uSurface.xwayland->y;
pbox->width = pWindow->m_uSurface.xwayland->width; if (SIZEHINTS && pWindow->m_iX11Type != 2) {
pbox->height = pWindow->m_uSurface.xwayland->height; pbox->x = SIZEHINTS->x;
pbox->y = SIZEHINTS->y;
pbox->width = SIZEHINTS->width;
pbox->height = SIZEHINTS->height;
} else {
pbox->x = pWindow->m_uSurface.xwayland->x;
pbox->y = pWindow->m_uSurface.xwayland->y;
pbox->width = pWindow->m_uSurface.xwayland->width;
pbox->height = pWindow->m_uSurface.xwayland->height;
}
} else { } else {
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, pbox); wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, pbox);
} }
@@ -248,7 +263,7 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(CWindow* pWindow) {
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return Vector2D(99999, 99999); return Vector2D(99999, 99999);
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel)) if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize)
return Vector2D(99999, 99999); return Vector2D(99999, 99999);
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height) auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height)

View File

@@ -49,6 +49,27 @@ void CInputManager::recheckIdleInhibitorStatus() {
} }
} }
// check manual user-set inhibitors
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_eIdleInhibitMode == IDLEINHIBIT_NONE)
continue;
if (w->m_eIdleInhibitMode == IDLEINHIBIT_ALWAYS) {
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false);
return;
}
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FOCUS && g_pCompositor->isWindowActive(w.get())) {
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false);
return;
}
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->m_bIsFullscreen && g_pCompositor->isWorkspaceVisible(w->m_iWorkspaceID)) {
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, false);
return;
}
}
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, true); wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, true);
return; return;
} }

View File

@@ -35,7 +35,16 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto *const PHOGFOCUS = &g_pConfigManager->getConfigValuePtr("misc:layers_hog_keyboard_focus")->intValue; static auto *const PHOGFOCUS = &g_pConfigManager->getConfigValuePtr("misc:layers_hog_keyboard_focus")->intValue;
static auto *const PFLOATBEHAVIOR = &g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus")->intValue; static auto *const PFLOATBEHAVIOR = &g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus")->intValue;
if (!g_pCompositor->m_bReadyToProcess) m_pFoundSurfaceToFocus = nullptr;
m_pFoundLSToFocus = nullptr;
m_pFoundWindowToFocus = nullptr;
wlr_surface* foundSurface = nullptr;
Vector2D surfaceCoords;
Vector2D surfacePos = Vector2D(-1337, -1337);
CWindow* pFoundWindow = nullptr;
SLayerSurface* pFoundLayerSurface = nullptr;
if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown)
return; return;
if (!g_pCompositor->m_sSeat.mouse) { if (!g_pCompositor->m_sSeat.mouse) {
@@ -43,9 +52,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return; return;
} }
if (g_pCompositor->m_sSeat.mouse->virt)
return; // don't refocus on virt
if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) { if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) {
// enable dpms // enable dpms
g_pKeybindManager->dpms("on"); g_pKeybindManager->dpms("on");
@@ -61,16 +67,15 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
bool didConstraintOnCursor = false;
// constraints // constraints
// All constraints TODO: multiple mice? // All constraints TODO: multiple mice?
if (g_pCompositor->m_sSeat.mouse->currentConstraint) { if (g_pCompositor->m_sSeat.mouse->currentConstraint && !g_pCompositor->m_sSeat.exclusiveClient) {
// XWayland windows sometimes issue constraints weirdly. // XWayland windows sometimes issue constraints weirdly.
// TODO: We probably should search their parent. wlr_xwayland_surface->parent // TODO: We probably should search their parent. wlr_xwayland_surface->parent
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse); const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
const auto PCONSTRAINT = constraintFromWlr(g_pCompositor->m_sSeat.mouse->currentConstraint);
if (!CONSTRAINTWINDOW) { if (!CONSTRAINTWINDOW || !PCONSTRAINT) {
unconstrainMouse(); unconstrainMouse();
} else { } else {
// Native Wayland apps know how 2 constrain themselves. // Native Wayland apps know how 2 constrain themselves.
@@ -78,32 +83,37 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
const auto CONSTRAINTPOS = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->x, CONSTRAINTWINDOW->m_uSurface.xwayland->y) : CONSTRAINTWINDOW->m_vRealPosition.vec(); const auto CONSTRAINTPOS = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->x, CONSTRAINTWINDOW->m_uSurface.xwayland->y) : CONSTRAINTWINDOW->m_vRealPosition.vec();
const auto CONSTRAINTSIZE = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->width, CONSTRAINTWINDOW->m_uSurface.xwayland->height) : CONSTRAINTWINDOW->m_vRealSize.vec(); const auto CONSTRAINTSIZE = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->width, CONSTRAINTWINDOW->m_uSurface.xwayland->height) : CONSTRAINTWINDOW->m_vRealSize.vec();
if (!VECINRECT(mouseCoords, CONSTRAINTPOS.x, CONSTRAINTPOS.y, CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0, CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0)) { if (g_pCompositor->m_sSeat.mouse->currentConstraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) {
if (g_pCompositor->m_sSeat.mouse->constraintActive) { // we just snap the cursor to where it should be.
Vector2D newConstrainedCoords = mouseCoords;
if (mouseCoords.x < CONSTRAINTPOS.x) Vector2D hint = { PCONSTRAINT->positionHint.x, PCONSTRAINT->positionHint.y };
newConstrainedCoords.x = CONSTRAINTPOS.x;
else if (mouseCoords.x >= CONSTRAINTPOS.x + CONSTRAINTSIZE.x)
newConstrainedCoords.x = CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0;
if (mouseCoords.y < CONSTRAINTPOS.y) wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, CONSTRAINTPOS.x + hint.x, CONSTRAINTPOS.y + hint.y);
newConstrainedCoords.y = CONSTRAINTPOS.y;
else if (mouseCoords.y >= CONSTRAINTPOS.y + CONSTRAINTSIZE.y)
newConstrainedCoords.y = CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0;
wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, newConstrainedCoords.x, newConstrainedCoords.y); return; // don't process anything else, the cursor is locked. The surface should not receive any further events.
// these are usually FPS games. They will use the relative motion.
mouseCoords = newConstrainedCoords;
didConstraintOnCursor = true;
}
} else { } else {
if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) { // we restrict the cursor to the confined region
g_pCompositor->m_sSeat.mouse->constraintActive = true; if (!pixman_region32_contains_point(&PCONSTRAINT->constraint->region, mouseCoords.x - CONSTRAINTPOS.x, mouseCoords.y - CONSTRAINTPOS.y, nullptr)) {
didConstraintOnCursor = true; if (g_pCompositor->m_sSeat.mouse->constraintActive) {
wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, NULL, mouseCoords.x, mouseCoords.y);
mouseCoords = getMouseCoordsInternal();
}
} else {
if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) {
g_pCompositor->m_sSeat.mouse->constraintActive = true;
}
} }
} }
if (CONSTRAINTWINDOW->m_bIsX11) {
foundSurface = g_pXWaylandManager->getWindowSurface(CONSTRAINTWINDOW);
surfacePos = CONSTRAINTWINDOW->m_vRealPosition.vec();
} else {
g_pCompositor->vectorWindowToSurface(mouseCoords, CONSTRAINTWINDOW, surfaceCoords);
}
pFoundWindow = CONSTRAINTWINDOW;
} }
} }
@@ -112,29 +122,15 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal()); g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal());
// focus
wlr_surface* foundSurface = nullptr;
if (didConstraintOnCursor)
return; // don't process when cursor constrained
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor) { if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor) {
g_pCompositor->m_pLastMonitor = PMONITOR; g_pCompositor->setActiveMonitor(PMONITOR);
// set active workspace and deactivate all other in wlr // set active workspace and deactivate all other in wlr
const auto ACTIVEWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto ACTIVEWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
g_pCompositor->deactivateAllWLRWorkspaces(ACTIVEWORKSPACE->m_pWlrHandle); g_pCompositor->deactivateAllWLRWorkspaces(ACTIVEWORKSPACE->m_pWlrHandle);
ACTIVEWORKSPACE->setActive(true); ACTIVEWORKSPACE->setActive(true);
// event
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName});
} }
Vector2D surfaceCoords;
Vector2D surfacePos = Vector2D(-1337, -1337);
CWindow* pFoundWindow = nullptr;
SLayerSurface* pFoundLayerSurface = nullptr;
// overlay is above fullscreen // overlay is above fullscreen
if (!foundSurface) if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface); foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface);
@@ -153,36 +149,32 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return; return;
} }
foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow);
surfacePos = pFoundWindow->m_vRealPosition.vec();
// only check floating because tiled cant be over fullscreen // only check floating because tiled cant be over fullscreen
for (auto w = g_pCompositor->m_vWindows.rbegin(); w != g_pCompositor->m_vWindows.rend(); w++) { for (auto w = g_pCompositor->m_vWindows.rbegin(); w != g_pCompositor->m_vWindows.rend(); w++) {
wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y}; wlr_box box = {(*w)->m_vRealPosition.vec().x, (*w)->m_vRealPosition.vec().y, (*w)->m_vRealSize.vec().x, (*w)->m_vRealSize.vec().y};
if ((((*w)->m_bIsFloating && (*w)->m_bIsMapped && ((*w)->m_bCreatedOverFullscreen || (*w)->m_bPinned)) || ((*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->m_bHidden) { if ((((*w)->m_bIsFloating && (*w)->m_bIsMapped && ((*w)->m_bCreatedOverFullscreen || (*w)->m_bPinned)) || (g_pCompositor->isWorkspaceSpecial((*w)->m_iWorkspaceID) && PMONITOR->specialWorkspaceID)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible((*w)->m_iWorkspaceID) && !(*w)->isHidden()) {
pFoundWindow = (*w).get(); pFoundWindow = (*w).get();
if (!pFoundWindow->m_bIsX11) {
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
surfacePos = Vector2D(-1337, -1337);
} else {
foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow);
surfacePos = pFoundWindow->m_vRealPosition.vec();
}
break; break;
} }
} }
if (!pFoundWindow->m_bIsX11) {
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
surfacePos = Vector2D(-1337, -1337);
} else {
foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow);
surfacePos = pFoundWindow->m_vRealPosition.vec();
}
} }
// then windows // then windows
if (!foundSurface) { if (!foundSurface) {
if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
if (PMONITOR->specialWorkspaceOpen) { if (PMONITOR->specialWorkspaceID) {
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (pFoundWindow && pFoundWindow->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) { if (pFoundWindow && !g_pCompositor->isWorkspaceSpecial(pFoundWindow->m_iWorkspaceID)) {
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
} }
} else { } else {
@@ -264,14 +256,21 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
} }
} }
// set the values for use
if (refocus) {
m_pFoundLSToFocus = pFoundLayerSurface;
m_pFoundWindowToFocus = pFoundWindow;
m_pFoundSurfaceToFocus = foundSurface;
}
if (pFoundWindow) { if (pFoundWindow) {
if (*PFOLLOWMOUSE != 1 && !refocus) { if (*PFOLLOWMOUSE != 1 && !refocus) {
if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR) { if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow && ((pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR == 2) || (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR != 0))) {
// enter if change floating style // enter if change floating style
if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus) if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface); g_pCompositor->focusWindow(pFoundWindow, foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} else if (*PFOLLOWMOUSE == 2) { } else if (*PFOLLOWMOUSE == 2 || *PFOLLOWMOUSE == 3) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} }
@@ -300,7 +299,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
} else { } else {
if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3 && allowKeyboardRefocus) { if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3 && allowKeyboardRefocus) {
g_pCompositor->focusSurface(foundSurface); g_pCompositor->focusSurface(foundSurface);
g_pCompositor->m_pLastWindow = nullptr; // reset last window as we have a full focus on a LS
} }
if (pFoundLayerSurface) if (pFoundLayerSurface)
@@ -338,6 +336,10 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
g_pHyprRenderer->m_bWindowRequestedCursorHide = false; g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
} }
if (m_bCursorImageOverriden) {
return;
}
if (m_ecbClickBehavior == CLICKMODE_KILL) { if (m_ecbClickBehavior == CLICKMODE_KILL) {
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor); wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor);
return; return;
@@ -376,27 +378,25 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
} }
void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
const auto PKEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat);
if (!PKEYBOARD) { // ???
Debug::log(ERR, "No active keyboard in processMouseDownNormal??");
return;
}
// notify the keybind manager // notify the keybind manager
static auto *const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue; static auto *const PPASSMOUSE = &g_pConfigManager->getConfigValuePtr("binds:pass_mouse_when_bound")->intValue;
const auto PASS = g_pKeybindManager->onMouseEvent(e); const auto PASS = g_pKeybindManager->onMouseEvent(e);
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
if (!PASS && !*PPASSMOUSE) if (!PASS && !*PPASSMOUSE)
return; return;
switch (e->state) { switch (e->state) {
case WLR_BUTTON_PRESSED: case WLR_BUTTON_PRESSED:
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
break;
if (!g_pCompositor->m_sSeat.mouse->currentConstraint) if (!g_pCompositor->m_sSeat.mouse->currentConstraint)
refocus(); refocus();
// if clicked on a floating window make it top // if clicked on a floating window make it top
if (g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_bIsFloating) if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsFloating)
g_pCompositor->moveWindowToTop(g_pCompositor->m_pLastWindow); g_pCompositor->moveWindowToTop(g_pCompositor->m_pLastWindow);
break; break;
@@ -415,7 +415,7 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
case WLR_BUTTON_PRESSED: { case WLR_BUTTON_PRESSED: {
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)){ if (!PWINDOW) {
Debug::log(ERR, "Cannot kill invalid window!"); Debug::log(ERR, "Cannot kill invalid window!");
break; break;
} }
@@ -435,12 +435,17 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
} }
void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) { void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
static auto *const PSCROLLFACTOR = &g_pConfigManager->getConfigValuePtr("input:touchpad:scroll_factor")->floatValue;
auto factor = (*PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : *PSCROLLFACTOR);
bool passEvent = g_pKeybindManager->onAxisEvent(e); bool passEvent = g_pKeybindManager->onAxisEvent(e);
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat); wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
if (passEvent) { if (passEvent) {
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, e->delta, e->delta_discrete, e->source); wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta,
std::round(factor * e->delta_discrete), e->source);
} }
} }
@@ -454,7 +459,7 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
PNEWKEYBOARD->keyboard = keyboard; PNEWKEYBOARD->keyboard = keyboard;
try { try {
PNEWKEYBOARD->name = std::string(keyboard->name); PNEWKEYBOARD->name = getNameForNewDevice(keyboard->name);
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Keyboard had no name???"); // logic error Debug::log(ERR, "Keyboard had no name???"); // logic error
} }
@@ -490,7 +495,7 @@ void CInputManager::newVirtualKeyboard(wlr_input_device* keyboard) {
PNEWKEYBOARD->isVirtual = true; PNEWKEYBOARD->isVirtual = true;
try { try {
PNEWKEYBOARD->name = std::string(keyboard->name); PNEWKEYBOARD->name = getNameForNewDevice(keyboard->name);
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Keyboard had no name???"); // logic error Debug::log(ERR, "Keyboard had no name???"); // logic error
} }
@@ -527,7 +532,6 @@ void CInputManager::setKeyboardLayout() {
void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
auto devname = pKeyboard->name; auto devname = pKeyboard->name;
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname); const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
@@ -651,7 +655,7 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
PMOUSE->mouse = mouse; PMOUSE->mouse = mouse;
PMOUSE->virt = virt; PMOUSE->virt = virt;
try { try {
PMOUSE->name = std::string(mouse->name); PMOUSE->name = getNameForNewDevice(mouse->name);
} catch(std::exception& e) { } catch(std::exception& e) {
Debug::log(ERR, "Mouse had no name???"); // logic error Debug::log(ERR, "Mouse had no name???"); // logic error
} }
@@ -662,12 +666,14 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
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)); 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(); wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, mouse);
PMOUSE->connected = true;
setPointerConfigs();
PMOUSE->hyprListener_destroyMouse.initCallback(&mouse->events.destroy, &Events::listener_destroyMouse, PMOUSE, "Mouse"); PMOUSE->hyprListener_destroyMouse.initCallback(&mouse->events.destroy, &Events::listener_destroyMouse, PMOUSE, "Mouse");
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, mouse);
g_pCompositor->m_sSeat.mouse = PMOUSE; g_pCompositor->m_sSeat.mouse = PMOUSE;
m_tmrLastCursorMovement.reset(); m_tmrLastCursorMovement.reset();
@@ -675,15 +681,25 @@ void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
Debug::log(LOG, "New mouse created, pointer WLR: %x", mouse); Debug::log(LOG, "New mouse created, pointer WLR: %x", mouse);
} }
void CInputManager::setMouseConfigs() { void CInputManager::setPointerConfigs() {
for (auto& m : m_lMice) { for (auto& m : m_lMice) {
const auto PMOUSE = &m; const auto PPOINTER = &m;
auto devname = PMOUSE->name; auto devname = PPOINTER->name;
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname); const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
if (HASCONFIG) {
const auto ENABLED = g_pConfigManager->getDeviceInt(devname, "enabled");
if (ENABLED && !m.connected) {
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, m.mouse);
m.connected = true;
} else if (!ENABLED && m.connected) {
wlr_cursor_detach_input_device(g_pCompositor->m_sWLRCursor, m.mouse);
m.connected = false;
}
}
if (wlr_input_device_is_libinput(m.mouse)) { if (wlr_input_device_is_libinput(m.mouse)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(m.mouse); const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(m.mouse);
@@ -692,6 +708,11 @@ void CInputManager::setMouseConfigs() {
else else
libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER); libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "left_handed") : g_pConfigManager->getInt("input:left_handed")) == 0)
libinput_device_config_left_handed_set(LIBINPUTDEV, 0);
else
libinput_device_config_left_handed_set(LIBINPUTDEV, 1);
if (libinput_device_config_middle_emulation_is_available(LIBINPUTDEV)) { // middleclick on r+l mouse button pressed 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) 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); libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED);
@@ -699,6 +720,21 @@ void CInputManager::setMouseConfigs() {
libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED);
} }
const auto SCROLLMETHOD = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "scroll_method") : g_pConfigManager->getString("input:scroll_method");
if (SCROLLMETHOD == "") {
libinput_device_config_scroll_set_method(LIBINPUTDEV, libinput_device_config_scroll_get_default_method(LIBINPUTDEV));
} else if (SCROLLMETHOD == "no_scroll") {
libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_NO_SCROLL);
} else if (SCROLLMETHOD == "2fg") {
libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_2FG);
} else if (SCROLLMETHOD == "edge") {
libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_EDGE);
} else if (SCROLLMETHOD == "on_button_down") {
libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN);
} else {
Debug::log(WARN, "Scroll method unknown");
}
if ((HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "drag_lock") : g_pConfigManager->getInt("input:touchpad:drag_lock")) == 0) 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); libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_DISABLED);
else else
@@ -723,10 +759,24 @@ void CInputManager::setMouseConfigs() {
} }
const auto LIBINPUTSENS = std::clamp((HASCONFIG ? g_pConfigManager->getDeviceFloat(devname, "sensitivity") : g_pConfigManager->getFloat("input:sensitivity")), -1.f, 1.f); 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); libinput_device_config_accel_set_speed(LIBINPUTDEV, LIBINPUTSENS);
const auto ACCELPROFILE = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "accel_profile") : g_pConfigManager->getString("input:accel_profile");
if (ACCELPROFILE == "") {
libinput_device_config_accel_set_profile(LIBINPUTDEV, libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
} else if (ACCELPROFILE == "adaptive") {
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
} else if (ACCELPROFILE == "flat") {
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
} else {
Debug::log(WARN, "Unknown acceleration profile, falling back to default");
}
const auto SCROLLBUTTON = HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "scroll_button") : g_pConfigManager->getInt("input:scroll_button");
libinput_device_config_scroll_set_button(LIBINPUTDEV, SCROLLBUTTON == 0 ? libinput_device_config_scroll_get_default_button(LIBINPUTDEV) : SCROLLBUTTON);
Debug::log(LOG, "Applied config to mouse %s, sens %.2f", m.name.c_str(), LIBINPUTSENS); Debug::log(LOG, "Applied config to mouse %s, sens %.2f", m.name.c_str(), LIBINPUTSENS);
} }
} }
@@ -765,6 +815,31 @@ void CInputManager::destroyMouse(wlr_input_device* mouse) {
unconstrainMouse(); unconstrainMouse();
} }
void CInputManager::updateKeyboardsLeds(wlr_input_device* pKeyboard) {
auto keyboard = wlr_keyboard_from_input_device(pKeyboard);
if (keyboard->xkb_state == NULL) {
return;
}
uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(keyboard->xkb_state,
keyboard->led_indexes[i])) {
leds |= (1 << i);
}
}
for (auto& kb : m_lKeyboards) {
if ((kb.isVirtual && shouldIgnoreVirtualKeyboard(&kb)) || kb.keyboard == pKeyboard)
continue;
wlr_keyboard_led_update(wlr_keyboard_from_input_device(kb.keyboard), leds);
}
}
void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) { void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
bool passEvent = g_pKeybindManager->onKeyEvent(e, pKeyboard); bool passEvent = g_pKeybindManager->onKeyEvent(e, pKeyboard);
@@ -781,6 +856,8 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard)); 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); wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e->time_msec, e->keycode, e->state);
} }
updateKeyboardsLeds(pKeyboard->keyboard);
} }
} }
@@ -800,6 +877,8 @@ void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &MODS); wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &MODS);
} }
updateKeyboardsLeds(pKeyboard->keyboard);
const auto PWLRKB = wlr_keyboard_from_input_device(pKeyboard->keyboard); const auto PWLRKB = wlr_keyboard_from_input_device(pKeyboard->keyboard);
if (PWLRKB->modifiers.group != pKeyboard->activeLayout) { if (PWLRKB->modifiers.group != pKeyboard->activeLayout) {
@@ -809,6 +888,10 @@ void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
} }
} }
bool CInputManager::shouldIgnoreVirtualKeyboard(SKeyboard* pKeyboard) {
return !pKeyboard || (m_sIMERelay.m_pKeyboardGrab && wl_resource_get_client(m_sIMERelay.m_pKeyboardGrab->pWlrKbGrab->resource) == wl_resource_get_client(wlr_input_device_get_virtual_keyboard(pKeyboard->keyboard)->resource));
}
void CInputManager::refocus() { void CInputManager::refocus() {
mouseMoveUnified(0, true); mouseMoveUnified(0, true);
} }
@@ -877,6 +960,12 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
wlr_seat_pointer_warp(constraint->seat, constraint->current.cursor_hint.x, constraint->current.cursor_hint.y); wlr_seat_pointer_warp(constraint->seat, constraint->current.cursor_hint.x, constraint->current.cursor_hint.y);
} }
} }
const auto PCONSTRAINT = constraintFromWlr(constraint);
if (PCONSTRAINT) { // should never be null but who knows
PCONSTRAINT->positionHint = Vector2D(constraint->current.cursor_hint.x, constraint->current.cursor_hint.y);
PCONSTRAINT->hintSet = true;
}
} }
} }
@@ -922,27 +1011,31 @@ void CInputManager::unconstrainMouse() {
} }
void Events::listener_commitConstraint(void* owner, void* data) { void Events::listener_commitConstraint(void* owner, void* data) {
//g_pInputManager->recheckConstraint((SMouse*)owner); const auto PMOUSE = (SMouse*)owner;
if (PMOUSE->currentConstraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) {
const auto PCONSTRAINT = g_pInputManager->constraintFromWlr(PMOUSE->currentConstraint);
if (PCONSTRAINT) { // should never be null but who knows
PCONSTRAINT->positionHint = Vector2D(PMOUSE->currentConstraint->current.cursor_hint.x, PMOUSE->currentConstraint->current.cursor_hint.y);
PCONSTRAINT->hintSet = true;
}
}
} }
void CInputManager::updateCapabilities(wlr_input_device* pDev) { void CInputManager::updateCapabilities() {
// TODO: this is dumb uint32_t caps = 0;
switch (pDev->type) { if (!m_lKeyboards.empty())
case WLR_INPUT_DEVICE_KEYBOARD: caps |= WL_SEAT_CAPABILITY_KEYBOARD;
m_uiCapabilities |= WL_SEAT_CAPABILITY_KEYBOARD; if (!m_lMice.empty())
break; caps |= WL_SEAT_CAPABILITY_POINTER;
case WLR_INPUT_DEVICE_POINTER: if (!m_lTouchDevices.empty())
m_uiCapabilities |= WL_SEAT_CAPABILITY_POINTER; caps |= WL_SEAT_CAPABILITY_TOUCH;
break; if (!m_lTabletTools.empty())
case WLR_INPUT_DEVICE_TOUCH: caps |= WL_SEAT_CAPABILITY_POINTER;
m_uiCapabilities |= WL_SEAT_CAPABILITY_TOUCH;
break;
default:
break;
}
wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, m_uiCapabilities); wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, caps);
m_uiCapabilities = caps;
} }
uint32_t CInputManager::accumulateModsFromAllKBs() { uint32_t CInputManager::accumulateModsFromAllKBs() {
@@ -950,7 +1043,7 @@ uint32_t CInputManager::accumulateModsFromAllKBs() {
uint32_t finalMask = 0; uint32_t finalMask = 0;
for (auto& kb : m_lKeyboards) { for (auto& kb : m_lKeyboards) {
if (kb.isVirtual) if (kb.isVirtual && shouldIgnoreVirtualKeyboard(&kb))
continue; continue;
finalMask |= wlr_keyboard_get_modifiers(wlr_keyboard_from_input_device(kb.keyboard)); finalMask |= wlr_keyboard_get_modifiers(wlr_keyboard_from_input_device(kb.keyboard));
@@ -992,6 +1085,13 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
const auto PNEWDEV = &m_lTouchDevices.emplace_back(); const auto PNEWDEV = &m_lTouchDevices.emplace_back();
PNEWDEV->pWlrDevice = pDevice; PNEWDEV->pWlrDevice = pDevice;
try {
PNEWDEV->name = getNameForNewDevice(pDevice->name);
} catch(std::exception& e) {
Debug::log(ERR, "Touch Device had no name???"); // logic error
}
setTouchDeviceConfigs();
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice); wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice);
Debug::log(LOG, "New touch device added at %x", PNEWDEV); Debug::log(LOG, "New touch device added at %x", PNEWDEV);
@@ -1001,8 +1101,145 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
}, PNEWDEV, "TouchDevice"); }, PNEWDEV, "TouchDevice");
} }
void CInputManager::setTouchDeviceConfigs() {
// The third row is always 0 0 1 and is not expected by `libinput_device_config_calibration_set_matrix`
static const float MATRICES[8][6] = {
{ // normal
1, 0, 0,
0, 1, 0
},
{ // rotation 90°
0, -1, 1,
1, 0, 0
},
{ // rotation 180°
-1, 0, 1,
0, -1, 1
},
{ // rotation 270°
0, 1, 0,
-1, 0, 1
},
{ // flipped
-1, 0, 1,
0, 1, 0
},
{ // flipped + rotation 90°
0, 1, 0,
1, 0, 0
},
{ // flipped + rotation 180°
1, 0, 0,
0, -1, 1
},
{ // flipped + rotation 270°
0, -1, 1,
-1, 0, 1
}
};
for (auto& m : m_lTouchDevices) {
const auto PTOUCHDEV = &m;
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(PTOUCHDEV->name);
if (wlr_input_device_is_libinput(m.pWlrDevice)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(m.pWlrDevice);
const int ROTATION = std::clamp(HASCONFIG ? g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "touch_transform") : g_pConfigManager->getInt("input:touchdevice:transform"), 0, 7);
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
const auto OUTPUT = HASCONFIG ? g_pConfigManager->getDeviceString(PTOUCHDEV->name, "touch_output") : g_pConfigManager->getString("input:touchdevice:output");
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY)
PTOUCHDEV->boundOutput = OUTPUT;
else
PTOUCHDEV->boundOutput = "";
}
}
}
void CInputManager::destroyTouchDevice(STouchDevice* pDevice) { void CInputManager::destroyTouchDevice(STouchDevice* pDevice) {
Debug::log(LOG, "Touch device at %x removed", pDevice); Debug::log(LOG, "Touch device at %x removed", pDevice);
m_lTouchDevices.remove(*pDevice); m_lTouchDevices.remove(*pDevice);
} }
void CInputManager::newSwitch(wlr_input_device* pDevice) {
const auto PNEWDEV = &m_lSwitches.emplace_back();
PNEWDEV->pWlrDevice = pDevice;
Debug::log(LOG, "New switch with name \"%s\" added", pDevice->name);
PNEWDEV->hyprListener_destroy.initCallback(&pDevice->events.destroy, [&](void* owner, void* data) {
destroySwitch((SSwitchDevice*)owner);
}, PNEWDEV, "SwitchDevice");
const auto PSWITCH = wlr_switch_from_input_device(pDevice);
PNEWDEV->hyprListener_toggle.initCallback(&PSWITCH->events.toggle, [&](void* owner, void* data) {
const auto PDEVICE = (SSwitchDevice*)owner;
const auto NAME = std::string(PDEVICE->pWlrDevice->name);
Debug::log(LOG, "Switch %s fired, triggering binds.", NAME.c_str());
g_pKeybindManager->onSwitchEvent(NAME);
}, PNEWDEV, "SwitchDevice");
}
void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
m_lSwitches.remove(*pDevice);
}
void CInputManager::setCursorImageUntilUnset(std::string name) {
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, name.c_str(), g_pCompositor->m_sWLRCursor);
m_bCursorImageOverriden = true;
}
void CInputManager::unsetCursorImage() {
if (!m_bCursorImageOverriden)
return;
m_bCursorImageOverriden = false;
if (!g_pHyprRenderer->m_bWindowRequestedCursorHide)
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
}
std::string CInputManager::deviceNameToInternalString(std::string in) {
std::replace(in.begin(), in.end(), ' ', '-');
std::transform(in.begin(), in.end(), in.begin(), ::tolower);
return in;
}
std::string CInputManager::getNameForNewDevice(std::string internalName) {
auto proposedNewName = deviceNameToInternalString(internalName);
int dupeno = 0;
while (std::find_if(m_lKeyboards.begin(), m_lKeyboards.end(), [&] (const SKeyboard& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lKeyboards.end())
dupeno++;
while (std::find_if(m_lMice.begin(), m_lMice.end(), [&] (const SMouse& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lMice.end())
dupeno++;
while (std::find_if(m_lTouchDevices.begin(), m_lTouchDevices.end(), [&] (const STouchDevice& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTouchDevices.end())
dupeno++;
while (std::find_if(m_lTabletPads.begin(), m_lTabletPads.end(), [&] (const STabletPad& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletPads.end())
dupeno++;
while (std::find_if(m_lTablets.begin(), m_lTablets.end(), [&] (const STablet& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTablets.end())
dupeno++;
while (std::find_if(m_lTabletTools.begin(), m_lTabletTools.end(), [&] (const STabletTool& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletTools.end())
dupeno++;
return proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno)));
}
SConstraint* CInputManager::constraintFromWlr(wlr_pointer_constraint_v1* constraint) {
for (auto& c : m_lConstraints) {
if (c.constraint == constraint)
return &c;
}
return nullptr;
}

View File

@@ -20,9 +20,13 @@ enum eMouseBindMode {
struct STouchData { struct STouchData {
CWindow* touchFocusWindow = nullptr; CWindow* touchFocusWindow = nullptr;
SLayerSurface* touchFocusLS = nullptr;
wlr_surface* touchFocusSurface = nullptr;
Vector2D touchSurfaceOrigin; Vector2D touchSurfaceOrigin;
}; };
class CKeybindManager;
class CInputManager { class CInputManager {
public: public:
@@ -37,23 +41,27 @@ public:
void newVirtualKeyboard(wlr_input_device*); void newVirtualKeyboard(wlr_input_device*);
void newMouse(wlr_input_device*, bool virt = false); void newMouse(wlr_input_device*, bool virt = false);
void newTouchDevice(wlr_input_device*); void newTouchDevice(wlr_input_device*);
void newSwitch(wlr_input_device*);
void destroyTouchDevice(STouchDevice*); void destroyTouchDevice(STouchDevice*);
void destroyKeyboard(SKeyboard*); void destroyKeyboard(SKeyboard*);
void destroyMouse(wlr_input_device*); void destroyMouse(wlr_input_device*);
void destroySwitch(SSwitchDevice*);
void constrainMouse(SMouse*, wlr_pointer_constraint_v1*); void constrainMouse(SMouse*, wlr_pointer_constraint_v1*);
void recheckConstraint(SMouse*); void recheckConstraint(SMouse*);
void unconstrainMouse(); void unconstrainMouse();
SConstraint* constraintFromWlr(wlr_pointer_constraint_v1*);
std::string getActiveLayoutForKeyboard(SKeyboard*); std::string getActiveLayoutForKeyboard(SKeyboard*);
Vector2D getMouseCoordsInternal(); Vector2D getMouseCoordsInternal();
void refocus(); void refocus();
void setKeyboardLayout(); void setKeyboardLayout();
void setMouseConfigs(); void setPointerConfigs();
void setTouchDeviceConfigs();
void updateDragIcon(); void updateDragIcon();
void updateCapabilities(wlr_input_device*); void updateCapabilities();
void setClickMode(eClickBehaviorMode); void setClickMode(eClickBehaviorMode);
eClickBehaviorMode getClickMode(); eClickBehaviorMode getClickMode();
@@ -89,6 +97,9 @@ public:
// Touch devices // Touch devices
std::list<STouchDevice> m_lTouchDevices; std::list<STouchDevice> m_lTouchDevices;
// Switches
std::list<SSwitchDevice> m_lSwitches;
void newTabletTool(wlr_input_device*); void newTabletTool(wlr_input_device*);
void newTabletPad(wlr_input_device*); void newTabletPad(wlr_input_device*);
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false); void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
@@ -107,13 +118,27 @@ public:
CInputMethodRelay m_sIMERelay; CInputMethodRelay m_sIMERelay;
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
// for shared mods // for shared mods
uint32_t accumulateModsFromAllKBs(); uint32_t accumulateModsFromAllKBs();
CWindow* m_pFollowOnDnDBegin = nullptr; CWindow* m_pFollowOnDnDBegin = nullptr;
// for virtual keyboards: whether we should respect them as normal ones
bool shouldIgnoreVirtualKeyboard(SKeyboard*);
// for special cursors that we choose
void setCursorImageUntilUnset(std::string);
void unsetCursorImage();
std::string deviceNameToInternalString(std::string);
std::string getNameForNewDevice(std::string);
private: private:
bool m_bCursorImageOverriden = false;
// for click behavior override // for click behavior override
eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT; eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT;
bool m_bEmptyFocusCursorSet = false; bool m_bEmptyFocusCursorSet = false;
@@ -134,6 +159,16 @@ private:
STabletTool* ensureTabletToolPresent(wlr_tablet_tool*); STabletTool* ensureTabletToolPresent(wlr_tablet_tool*);
void applyConfigToKeyboard(SKeyboard*); void applyConfigToKeyboard(SKeyboard*);
// this will be set after a refocus()
wlr_surface* m_pFoundSurfaceToFocus = nullptr;
SLayerSurface* m_pFoundLSToFocus = nullptr;
CWindow* m_pFoundWindowToFocus = nullptr;
// swipe
void beginWorkspaceSwipe();
friend class CKeybindManager;
}; };
inline std::unique_ptr<CInputManager> g_pInputManager; inline std::unique_ptr<CInputManager> g_pInputManager;

View File

@@ -301,7 +301,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
const auto PINPUT = (STextInput*)owner; const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) { if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(ERR, "Enabling TextInput on no IME!"); // Debug::log(WARN, "Enabling TextInput on no IME!");
return; return;
} }
@@ -317,12 +317,12 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
const auto PINPUT = (STextInput*)owner; const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) { if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(ERR, "Committing TextInput on no IME!"); // Debug::log(WARN, "Committing TextInput on no IME!");
return; return;
} }
if (!PINPUT->pWlrInput->current_enabled) { if (!PINPUT->pWlrInput->current_enabled) {
Debug::log(ERR, "Disabled TextInput commit?"); Debug::log(WARN, "Disabled TextInput commit?");
return; return;
} }
@@ -335,7 +335,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
const auto PINPUT = (STextInput*)owner; const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) { if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(ERR, "Disabling TextInput on no IME!"); // Debug::log(WARN, "Disabling TextInput on no IME!");
return; return;
} }
@@ -352,7 +352,7 @@ void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput) {
const auto PINPUT = (STextInput*)owner; const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) { if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
Debug::log(ERR, "Disabling TextInput on no IME!"); // Debug::log(WARN, "Disabling TextInput on no IME!");
return; return;
} }

View File

@@ -3,6 +3,8 @@
#include "../../defines.hpp" #include "../../defines.hpp"
#include "../../helpers/WLClasses.hpp" #include "../../helpers/WLClasses.hpp"
class CInputManager;
class CInputMethodRelay { class CInputMethodRelay {
public: public:
CInputMethodRelay(); CInputMethodRelay();
@@ -45,4 +47,5 @@ private:
void createNewTextInput(wlr_text_input_v3*); void createNewTextInput(wlr_text_input_v3*);
friend class CHyprRenderer; friend class CHyprRenderer;
friend class CInputManager;
}; };

View File

@@ -4,20 +4,25 @@
void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) { void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
static auto *const PSWIPE = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe")->intValue; static auto *const PSWIPE = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe")->intValue;
static auto *const PSWIPEFINGERS = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_fingers")->intValue; static auto *const PSWIPEFINGERS = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_fingers")->intValue;
static auto *const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue;
if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0) if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0)
return; return;
int onMonitor = 0; int onMonitor = 0;
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && w->m_iID != SPECIAL_WORKSPACE_ID) { if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && !g_pCompositor->isWorkspaceSpecial(w->m_iID)) {
onMonitor++; onMonitor++;
} }
} }
if (onMonitor < 2) if (onMonitor < 2 && !*PSWIPENEW)
return; // disallow swiping when there's 1 workspace on a monitor return; // disallow swiping when there's 1 workspace on a monitor
beginWorkspaceSwipe();
}
void CInputManager::beginWorkspaceSwipe() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
Debug::log(LOG, "Starting a swipe from %s", PWORKSPACE->m_szName.c_str()); Debug::log(LOG, "Starting a swipe from %s", PWORKSPACE->m_szName.c_str());
@@ -42,13 +47,19 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
static auto *const PSWIPEPERC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_cancel_ratio")->floatValue; static auto *const PSWIPEPERC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_cancel_ratio")->floatValue;
static auto *const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue; static auto *const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue;
static auto *const PSWIPEFORC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_min_speed_to_force")->intValue; static auto *const PSWIPEFORC = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_min_speed_to_force")->intValue;
static auto *const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert";
// commit // commit
std::string wsname = ""; std::string wsname = "";
auto workspaceIDLeft = getWorkspaceIDFromString("m-1", wsname); auto workspaceIDLeft = getWorkspaceIDFromString("m-1", wsname);
auto workspaceIDRight = getWorkspaceIDFromString("m+1", wsname); auto workspaceIDRight = getWorkspaceIDFromString("m+1", wsname);
const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); if ((workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID || (workspaceIDRight == workspaceIDLeft && workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID)) && *PSWIPENEW) {
workspaceIDRight = m_sActiveSwipe.pWorkspaceBegin->m_iID > 0 ? m_sActiveSwipe.pWorkspaceBegin->m_iID + 1 : 1;
}
auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW
const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.vec(); const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.vec();
@@ -59,15 +70,22 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
// revert // revert
if (abs(m_sActiveSwipe.delta) < 2) { if (abs(m_sActiveSwipe.delta) < 2) {
PWORKSPACEL->m_vRenderOffset.setValueAndWarp(Vector2D(0,0)); PWORKSPACEL->m_vRenderOffset.setValueAndWarp(Vector2D(0,0));
PWORKSPACER->m_vRenderOffset.setValueAndWarp(Vector2D(0,0)); if (PWORKSPACER)
PWORKSPACER->m_vRenderOffset.setValueAndWarp(Vector2D(0,0));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0,0)); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0,0));
} else { } else {
if (m_sActiveSwipe.delta < 0) { if (m_sActiveSwipe.delta < 0) {
// to left // to left
PWORKSPACEL->m_vRenderOffset = Vector2D({-m_sActiveSwipe.pMonitor->vecSize.x, 0}); if (VERTANIMS)
} else { PWORKSPACEL->m_vRenderOffset = Vector2D({0, -m_sActiveSwipe.pMonitor->vecSize.y});
else
PWORKSPACEL->m_vRenderOffset = Vector2D({-m_sActiveSwipe.pMonitor->vecSize.x, 0});
} else if (PWORKSPACER) {
// to right // to right
PWORKSPACER->m_vRenderOffset = Vector2D({m_sActiveSwipe.pMonitor->vecSize.x, 0}); if (VERTANIMS)
PWORKSPACER->m_vRenderOffset = Vector2D({0, m_sActiveSwipe.pMonitor->vecSize.y});
else
PWORKSPACER->m_vRenderOffset = Vector2D({m_sActiveSwipe.pMonitor->vecSize.x, 0});
} }
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D();
@@ -84,7 +102,10 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
PWORKSPACEL->m_fAlpha.setValueAndWarp(255.f); PWORKSPACEL->m_fAlpha.setValueAndWarp(255.f);
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE);
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(m_sActiveSwipe.pMonitor->vecSize.x, 0); if (VERTANIMS)
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, m_sActiveSwipe.pMonitor->vecSize.y);
else
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(m_sActiveSwipe.pMonitor->vecSize.x, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f); m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f);
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
@@ -94,15 +115,24 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
pSwitchedTo = PWORKSPACEL; pSwitchedTo = PWORKSPACEL;
} else { } else {
// switch to right // switch to right
const auto RENDEROFFSET = PWORKSPACER->m_vRenderOffset.vec(); const auto RENDEROFFSET = PWORKSPACER ? PWORKSPACER->m_vRenderOffset.vec() : Vector2D();
g_pKeybindManager->m_mDispatchers["workspace"]("[internal]" + std::to_string(workspaceIDRight)); if (PWORKSPACER)
g_pKeybindManager->m_mDispatchers["workspace"]("[internal]" + std::to_string(workspaceIDRight));
else
g_pKeybindManager->m_mDispatchers["workspace"](std::to_string(workspaceIDRight)); // so that the ID is created properly
if (!PWORKSPACER)
PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed on PSWIPENEW
PWORKSPACER->m_vRenderOffset.setValue(RENDEROFFSET); PWORKSPACER->m_vRenderOffset.setValue(RENDEROFFSET);
PWORKSPACER->m_fAlpha.setValueAndWarp(255.f); PWORKSPACER->m_fAlpha.setValueAndWarp(255.f);
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE);
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-m_sActiveSwipe.pMonitor->vecSize.x, 0); if (VERTANIMS)
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, -m_sActiveSwipe.pMonitor->vecSize.y);
else
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-m_sActiveSwipe.pMonitor->vecSize.x, 0);
m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f); m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(255.f);
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
@@ -115,7 +145,8 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
PWORKSPACEL->m_bForceRendering = false; PWORKSPACEL->m_bForceRendering = false;
PWORKSPACER->m_bForceRendering = false; if (PWORKSPACER)
PWORKSPACER->m_bForceRendering = false;
m_sActiveSwipe.pWorkspaceBegin->m_bForceRendering = false; m_sActiveSwipe.pWorkspaceBegin->m_bForceRendering = false;
m_sActiveSwipe.pWorkspaceBegin = nullptr; m_sActiveSwipe.pWorkspaceBegin = nullptr;
@@ -124,7 +155,7 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
// apply alpha // apply alpha
for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
ls->alpha = pSwitchedTo->m_bHasFullscreenWindow ? 0.f : 255.f; ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 255.f;
} }
} }
@@ -134,8 +165,12 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
static auto *const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue; static auto *const PSWIPEDIST = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_distance")->intValue;
static auto *const PSWIPEINVR = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_invert")->intValue; static auto *const PSWIPEINVR = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_invert")->intValue;
static auto *const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue;
static auto *const PSWIPEFOREVER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_forever")->intValue;
m_sActiveSwipe.delta += *PSWIPEINVR ? -e->dx : e->dx; const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert";
m_sActiveSwipe.delta += VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx);
m_sActiveSwipe.avgSpeed = (m_sActiveSwipe.avgSpeed * m_sActiveSwipe.speedPoints + abs(e->dx)) / (m_sActiveSwipe.speedPoints + 1); m_sActiveSwipe.avgSpeed = (m_sActiveSwipe.avgSpeed * m_sActiveSwipe.speedPoints + abs(e->dx)) / (m_sActiveSwipe.speedPoints + 1);
m_sActiveSwipe.speedPoints++; m_sActiveSwipe.speedPoints++;
@@ -144,7 +179,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
auto workspaceIDLeft = getWorkspaceIDFromString("m-1", wsname); auto workspaceIDLeft = getWorkspaceIDFromString("m-1", wsname);
auto workspaceIDRight = getWorkspaceIDFromString("m+1", wsname); auto workspaceIDRight = getWorkspaceIDFromString("m+1", wsname);
if (workspaceIDLeft == INT_MAX || workspaceIDRight == INT_MAX || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) { if ((workspaceIDLeft == INT_MAX || workspaceIDRight == INT_MAX || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) && !*PSWIPENEW) {
m_sActiveSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe m_sActiveSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe
return; return;
} }
@@ -153,8 +188,16 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
m_sActiveSwipe.delta = std::clamp(m_sActiveSwipe.delta, (double)-*PSWIPEDIST, (double)*PSWIPEDIST); m_sActiveSwipe.delta = std::clamp(m_sActiveSwipe.delta, (double)-*PSWIPEDIST, (double)*PSWIPEDIST);
if ((m_sActiveSwipe.pWorkspaceBegin->m_iID == workspaceIDLeft && *PSWIPENEW && (m_sActiveSwipe.delta < 0)) ||
(m_sActiveSwipe.delta > 0 && g_pCompositor->getWindowsOnWorkspace(m_sActiveSwipe.pWorkspaceBegin->m_iID) == 0 && workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID) ||
(m_sActiveSwipe.delta < 0 && m_sActiveSwipe.pWorkspaceBegin->m_iID <= workspaceIDLeft)) {
m_sActiveSwipe.delta = 0;
return;
}
if (m_sActiveSwipe.delta < 0) { if (m_sActiveSwipe.delta < 0) {
if (workspaceIDLeft > m_sActiveSwipe.pWorkspaceBegin->m_iID){ if (workspaceIDLeft > m_sActiveSwipe.pWorkspaceBegin->m_iID && !*PSWIPENEW){
m_sActiveSwipe.delta = 0; m_sActiveSwipe.delta = 0;
return; return;
} }
@@ -171,12 +214,28 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
PWORKSPACER->m_fAlpha.setValueAndWarp(0.f); PWORKSPACER->m_fAlpha.setValueAndWarp(0.f);
} }
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x - m_sActiveSwipe.pMonitor->vecSize.x, 0)); if (VERTANIMS) {
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0)); PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y - m_sActiveSwipe.pMonitor->vecSize.y));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y));
} else {
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x - m_sActiveSwipe.pMonitor->vecSize.x, 0));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0));
}
g_pCompositor->updateWorkspaceWindowDecos(workspaceIDLeft); g_pCompositor->updateWorkspaceWindowDecos(workspaceIDLeft);
} else { } else {
if (workspaceIDRight < m_sActiveSwipe.pWorkspaceBegin->m_iID){ if (workspaceIDRight < m_sActiveSwipe.pWorkspaceBegin->m_iID) {
if (*PSWIPENEW) {
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
if (VERTANIMS)
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y));
else
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0));
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
return;
}
m_sActiveSwipe.delta = 0; m_sActiveSwipe.delta = 0;
return; return;
} }
@@ -193,8 +252,13 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
PWORKSPACEL->m_fAlpha.setValueAndWarp(0.f); PWORKSPACEL->m_fAlpha.setValueAndWarp(0.f);
} }
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x + m_sActiveSwipe.pMonitor->vecSize.x, 0)); if (VERTANIMS) {
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0)); PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y + m_sActiveSwipe.pMonitor->vecSize.y));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.y));
} else {
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x + m_sActiveSwipe.pMonitor->vecSize.x, 0));
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x, 0));
}
g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight); g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight);
} }
@@ -202,4 +266,11 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID);
if (*PSWIPEFOREVER) {
if (abs(m_sActiveSwipe.delta) >= *PSWIPEDIST) {
onSwipeEnd(nullptr);
beginWorkspaceSwipe();
}
}
} }

View File

@@ -5,7 +5,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
const auto PNEWTABLET = &m_lTablets.emplace_back(); const auto PNEWTABLET = &m_lTablets.emplace_back();
try { try {
PNEWTABLET->name = std::string(pDevice->name); PNEWTABLET->name = deviceNameToInternalString(pDevice->name);
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Tablet had no name???"); // logic error Debug::log(ERR, "Tablet had no name???"); // logic error
} }
@@ -158,7 +158,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) {
const auto PNEWPAD = &m_lTabletPads.emplace_back(); const auto PNEWPAD = &m_lTabletPads.emplace_back();
try { try {
PNEWPAD->name = std::string(pDevice->name); PNEWPAD->name = deviceNameToInternalString(pDevice->name);
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Pad had no name???"); // logic error Debug::log(ERR, "Pad had no name???"); // logic error
} }
@@ -219,7 +219,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) {
void CInputManager::focusTablet(STablet* pTab, wlr_tablet_tool* pTool, bool motion) { void CInputManager::focusTablet(STablet* pTab, wlr_tablet_tool* pTool, bool motion) {
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(pTool); const auto PTOOL = g_pInputManager->ensureTabletToolPresent(pTool);
if (const auto PWINDOW = g_pCompositor->m_pLastWindow; g_pCompositor->windowValidMapped(PWINDOW)) { if (const auto PWINDOW = g_pCompositor->m_pLastWindow; PWINDOW) {
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal(); const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
const auto LOCAL = CURSORPOS - PWINDOW->m_vRealPosition.goalv(); const auto LOCAL = CURSORPOS - PWINDOW->m_vRealPosition.goalv();

View File

@@ -2,42 +2,68 @@
#include "../../Compositor.hpp" #include "../../Compositor.hpp"
void CInputManager::onTouchDown(wlr_touch_down_event* e) { void CInputManager::onTouchDown(wlr_touch_down_event* e) {
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, g_pCompositor->m_pLastMonitor->vecPosition.x + e->x * g_pCompositor->m_pLastMonitor->vecSize.x, g_pCompositor->m_pLastMonitor->vecPosition.y + e->y * g_pCompositor->m_pLastMonitor->vecSize.y); auto PMONITOR = g_pCompositor->getMonitorFromName(e->touch->output_name ? e->touch->output_name : "");
const auto PDEVIT = std::find_if(m_lTouchDevices.begin(), m_lTouchDevices.end(), [&](const STouchDevice& other) { return other.pWlrDevice == &e->touch->base; });
if (PDEVIT != m_lTouchDevices.end() && !PDEVIT->boundOutput.empty())
PMONITOR = g_pCompositor->getMonitorFromName(PDEVIT->boundOutput);
PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor;
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
refocus(); refocus();
m_sTouchData.touchFocusWindow = nullptr; m_sTouchData.touchFocusWindow = m_pFoundWindowToFocus;
m_sTouchData.touchFocusSurface = m_pFoundSurfaceToFocus;
m_sTouchData.touchFocusLS = m_pFoundLSToFocus;
if (g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow)) { Vector2D local;
Vector2D local;
if (g_pCompositor->m_pLastWindow->m_bIsX11) { if (m_sTouchData.touchFocusWindow) {
local = g_pInputManager->getMouseCoordsInternal() - g_pCompositor->m_pLastWindow->m_vRealPosition.goalv(); if (m_sTouchData.touchFocusWindow->m_bIsX11) {
local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition.goalv();
} else { } else {
g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), g_pCompositor->m_pLastWindow, local); g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), m_sTouchData.touchFocusWindow, local);
} }
m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local; m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local;
} else if (m_sTouchData.touchFocusLS) {
local = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_sTouchData.touchFocusLS->geometry.x, m_sTouchData.touchFocusLS->geometry.y) - g_pCompositor->m_pLastMonitor->vecPosition;
wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, g_pCompositor->m_pLastFocus, e->time_msec, e->touch_id, local.x, local.y); m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local;
} else {
m_sTouchData.touchFocusWindow = g_pCompositor->m_pLastWindow; return; // oops, nothing found.
} }
wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e->time_msec, e->touch_id, local.x, local.y);
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
} }
void CInputManager::onTouchUp(wlr_touch_up_event* e){ void CInputManager::onTouchUp(wlr_touch_up_event* e){
if (m_sTouchData.touchFocusWindow) { if (m_sTouchData.touchFocusSurface) {
wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id); wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id);
} }
} }
void CInputManager::onTouchMove(wlr_touch_motion_event* e){ void CInputManager::onTouchMove(wlr_touch_motion_event* e){
if (g_pCompositor->windowValidMapped(m_sTouchData.touchFocusWindow)) { if (m_sTouchData.touchFocusWindow && g_pCompositor->windowValidMapped(m_sTouchData.touchFocusWindow)) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin; const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
} else if (m_sTouchData.touchFocusLS) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y); wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
} }
} }

View File

@@ -1,4 +1,4 @@
globber = run_command('find', '-name', '*.cpp', check: true) globber = run_command('find', '.', '-name', '*.cpp', check: true)
src = globber.stdout().strip().split('\n') src = globber.stdout().strip().split('\n')
executable('Hyprland', src, executable('Hyprland', src,
@@ -18,7 +18,7 @@ executable('Hyprland', src,
xcb_dep, xcb_dep,
dependency('pixman-1'), dependency('pixman-1'),
dependency('GL'), dependency('gl', 'opengl'),
dependency('threads') dependency('threads')
], ],
install : true install : true

View File

@@ -0,0 +1,400 @@
#include "ToplevelExport.hpp"
#include "../Compositor.hpp"
#include <drm_fourcc.h>
#include <algorithm>
#include "ToplevelExportWlrFuncs.hpp"
#define TOPLEVEL_EXPORT_VERSION 2
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
g_pProtocolManager->m_pToplevelExportProtocolManager->bindManager(client, data, version, id);
}
static void handleDisplayDestroy(struct wl_listener* listener, void* data) {
g_pProtocolManager->m_pToplevelExportProtocolManager->displayDestroy();
}
void CToplevelExportProtocolManager::displayDestroy() {
wl_global_destroy(m_pGlobal);
}
CToplevelExportProtocolManager::CToplevelExportProtocolManager() {
#ifndef GLES32
Debug::log(WARN, "Toplevel sharing is not supported on LEGACY_RENDERER!");
return;
#endif
m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &hyprland_toplevel_export_manager_v1_interface,
TOPLEVEL_EXPORT_VERSION, this, bindManagerInt);
if (!m_pGlobal) {
Debug::log(ERR, "ToplevelExportManager could not start! Sharing windows will not work!");
return;
}
m_liDisplayDestroy.notify = handleDisplayDestroy;
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
Debug::log(LOG, "ToplevelExportManager started successfully!");
}
wlr_foreign_toplevel_handle_v1* zwlrHandleFromResource(wl_resource* resource) {
// we can't assert here, but it doesnt matter.
return (wlr_foreign_toplevel_handle_v1*)wl_resource_get_user_data(resource);
}
void handleCaptureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) {
g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromHandle(handle));
}
void handleCaptureToplevelWithWlr(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* handle) {
g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromZWLRHandle(handle));
}
void handleDestroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
g_pProtocolManager->m_pToplevelExportProtocolManager->copyFrame(client, resource, buffer, ignore_damage);
}
void handleDestroyFrame(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
static const struct hyprland_toplevel_export_manager_v1_interface toplevelExportManagerImpl = {
.capture_toplevel = handleCaptureToplevel,
.destroy = handleDestroy,
.capture_toplevel_with_wlr_toplevel_handle = handleCaptureToplevelWithWlr,
};
static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = {
.copy = handleCopyFrame,
.destroy = handleDestroyFrame
};
SToplevelClient* clientFromResource(wl_resource* resource) {
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_manager_v1_interface, &toplevelExportManagerImpl));
return (SToplevelClient*)wl_resource_get_user_data(resource);
}
SToplevelFrame* frameFromResource(wl_resource* resource) {
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_frame_v1_interface, &toplevelFrameImpl));
return (SToplevelFrame*)wl_resource_get_user_data(resource);
}
void CToplevelExportProtocolManager::removeClient(SToplevelClient* client, bool force) {
if (!force) {
if (!client || client->ref <= 0)
return;
if (--client->ref != 0)
return;
}
m_lClients.remove(*client); // TODO: this doesn't get cleaned up after sharing app exits???
}
void handleManagerResourceDestroy(wl_resource* resource) {
const auto PCLIENT = clientFromResource(resource);
g_pProtocolManager->m_pToplevelExportProtocolManager->removeClient(PCLIENT, true);
}
void CToplevelExportProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
const auto PCLIENT = &m_lClients.emplace_back();
PCLIENT->resource = wl_resource_create(client, &hyprland_toplevel_export_manager_v1_interface,
version, id);
if (!PCLIENT->resource) {
Debug::log(ERR, "ToplevelExportManager could not bind! (out of memory?)");
m_lClients.remove(*PCLIENT);
wl_client_post_no_memory(client);
return;
}
PCLIENT->ref = 1;
wl_resource_set_implementation(PCLIENT->resource, &toplevelExportManagerImpl, PCLIENT, handleManagerResourceDestroy);
Debug::log(LOG, "ToplevelExportManager bound successfully!");
}
void handleFrameResourceDestroy(wl_resource* resource) {
const auto PFRAME = frameFromResource(resource);
g_pProtocolManager->m_pToplevelExportProtocolManager->removeFrame(PFRAME);
}
void CToplevelExportProtocolManager::removeFrame(SToplevelFrame* frame, bool force) {
if (!frame)
return;
std::erase_if(m_vFramesAwaitingWrite, [&] (const auto& other) { return other == frame; });
wl_resource_set_user_data(frame->resource, nullptr);
wlr_buffer_unlock(frame->buffer);
removeClient(frame->client, force);
m_lFrames.remove(*frame);
}
void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, CWindow* pWindow) {
const auto PCLIENT = clientFromResource(resource);
// create a frame
const auto PFRAME = &m_lFrames.emplace_back();
PFRAME->overlayCursor = !!overlay_cursor;
PFRAME->resource = wl_resource_create(client, &hyprland_toplevel_export_frame_v1_interface, wl_resource_get_version(resource), frame);
PFRAME->pWindow = pWindow;
if (!PFRAME->pWindow) {
Debug::log(ERR, "Client requested sharing of window handle %x which does not exist!", PFRAME->pWindow);
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
removeFrame(PFRAME);
return;
}
if (!PFRAME->pWindow->m_bIsMapped || PFRAME->pWindow->isHidden()) {
Debug::log(ERR, "Client requested sharing of window handle %x which is not shareable!", PFRAME->pWindow);
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
removeFrame(PFRAME);
return;
}
if (!PFRAME->resource) {
Debug::log(ERR, "Couldn't alloc frame for sharing! (no memory)");
m_lFrames.remove(*PFRAME);
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(PFRAME->resource, &toplevelFrameImpl, PFRAME, handleFrameResourceDestroy);
PFRAME->client = PCLIENT;
PCLIENT->ref++;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PFRAME->pWindow->m_iMonitorID);
PFRAME->shmFormat = wlr_output_preferred_read_format(PMONITOR->output);
if (PFRAME->shmFormat == DRM_FORMAT_INVALID) {
Debug::log(ERR, "No format supported by renderer in capture toplevel");
hyprland_toplevel_export_frame_v1_send_failed(resource);
removeFrame(PFRAME);
return;
}
const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat);
if (!PSHMINFO) {
Debug::log(ERR, "No pixel format supported by renderer in capture toplevel");
hyprland_toplevel_export_frame_v1_send_failed(resource);
removeFrame(PFRAME);
return;
}
if (PMONITOR->output->allocator && (PMONITOR->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) {
PFRAME->dmabufFormat = PMONITOR->output->render_format;
} else {
PFRAME->dmabufFormat = DRM_FORMAT_INVALID;
}
PFRAME->box = { 0, 0, (int)(PFRAME->pWindow->m_vRealSize.vec().x * PMONITOR->scale), (int)(PFRAME->pWindow->m_vRealSize.vec().y * PMONITOR->scale) };
int ow, oh;
wlr_output_effective_resolution(PMONITOR->output, &ow, &oh);
wlr_box_transform(&PFRAME->box, &PFRAME->box, PMONITOR->transform, ow, oh);
PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width;
hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
}
void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
const auto PFRAME = frameFromResource(resource);
if (!PFRAME) {
Debug::log(ERR, "No frame in copyFrame??");
return;
}
if (!PFRAME->pWindow->m_bIsMapped || PFRAME->pWindow->isHidden()) {
Debug::log(ERR, "Client requested sharing of window handle %x which is not shareable (2)!", PFRAME->pWindow);
hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource);
removeFrame(PFRAME);
return;
}
const auto PBUFFER = wlr_buffer_from_resource(buffer);
if (!PBUFFER) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
removeFrame(PFRAME);
return;
}
if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
removeFrame(PFRAME);
return;
}
if (PFRAME->buffer) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_ALREADY_USED, "frame already used");
removeFrame(PFRAME);
return;
}
wlr_dmabuf_attributes dmabufAttrs;
void* wlrBufferAccessData;
uint32_t wlrBufferAccessFormat;
size_t wlrBufferAccessStride;
if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) {
PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF;
if (dmabufAttrs.format != PFRAME->dmabufFormat) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
removeFrame(PFRAME);
return;
}
} else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) {
wlr_buffer_end_data_ptr_access(PBUFFER);
if (wlrBufferAccessFormat != PFRAME->shmFormat) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
removeFrame(PFRAME);
return;
} else if ((int)wlrBufferAccessStride != PFRAME->shmStride) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
removeFrame(PFRAME);
return;
}
} else {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type");
removeFrame(PFRAME);
return;
}
PFRAME->buffer = PBUFFER;
m_vFramesAwaitingWrite.emplace_back(PFRAME);
}
void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) {
if (m_vFramesAwaitingWrite.empty())
return; // nothing to share
std::vector<SToplevelFrame*> framesToRemove;
// share frame if correct output
for (auto& f : m_vFramesAwaitingWrite) {
if (!f->pWindow) {
framesToRemove.push_back(f);
continue;
}
wlr_box geometry = { f->pWindow->m_vRealPosition.vec().x, f->pWindow->m_vRealPosition.vec().y,
f->pWindow->m_vRealSize.vec().x, f->pWindow->m_vRealSize.vec().y };
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry))
continue;
shareFrame(f);
framesToRemove.push_back(f);
}
for (auto& f : framesToRemove) {
removeFrame(f);
}
}
void CToplevelExportProtocolManager::shareFrame(SToplevelFrame* frame) {
if (!frame->buffer) {
return;
}
// TODO: damage
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
uint32_t flags = 0;
if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
if (!copyFrameDmabuf(frame)) {
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
return;
}
} else {
if (!copyFrameShm(frame, &now)) {
hyprland_toplevel_export_frame_v1_send_failed(frame->resource);
return;
}
}
hyprland_toplevel_export_frame_v1_send_flags(frame->resource, flags);
// todo: send damage
uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0;
uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF;
hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
}
bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespec* now) {
void* data;
uint32_t format;
size_t stride;
if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride))
return false;
// render the client
const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID);
pixman_region32_t fakeDamage;
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10);
g_pHyprOpenGL->begin(PMONITOR, &fakeDamage, true);
g_pHyprOpenGL->clear(CColor(0, 0, 0, 255));
// render client at 0,0
g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(frame->pWindow); // block the feedback to avoid spamming the surface if it's visible
g_pHyprRenderer->renderWindow(frame->pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true);
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
// copy pixels
const auto PFORMAT = get_gles2_format_from_drm(format);
if (!PFORMAT) {
Debug::log(ERR, "Cannot read pixels, unsupported format %x", PFORMAT);
g_pHyprOpenGL->end();
pixman_region32_fini(&fakeDamage);
wlr_buffer_end_data_ptr_access(frame->buffer);
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_iFb);
glFinish(); // flush
glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->gl_format, PFORMAT->gl_type, data);
g_pHyprOpenGL->end();
pixman_region32_fini(&fakeDamage);
wlr_buffer_end_data_ptr_access(frame->buffer);
return true;
}
bool CToplevelExportProtocolManager::copyFrameDmabuf(SToplevelFrame* frame) {
// todo
Debug::log(ERR, "DMABUF copying not impl'd!");
return false;
}
void CToplevelExportProtocolManager::onWindowUnmap(CWindow* pWindow) {
for (auto& f : m_lFrames) {
if (f.pWindow == pWindow)
f.pWindow = nullptr;
}
}

View File

@@ -0,0 +1,70 @@
#pragma once
#include "../defines.hpp"
#include "wlr-foreign-toplevel-management-unstable-v1-protocol.h"
#include "hyprland-toplevel-export-v1-protocol.h"
#include <list>
#include <vector>
class CMonitor;
class CWindow;
struct SToplevelClient {
int ref = 0;
wl_resource* resource = nullptr;
bool operator==(const SToplevelClient& other) {
return resource == other.resource;
}
};
struct SToplevelFrame {
wl_resource* resource = nullptr;
SToplevelClient* client = nullptr;
uint32_t shmFormat = 0;
uint32_t dmabufFormat = 0;
wlr_box box = { 0 };
int shmStride = 0;
bool overlayCursor = false;
wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM;
wlr_buffer* buffer = nullptr;
CWindow* pWindow = nullptr;
bool operator==(const SToplevelFrame& other) {
return resource == other.resource && client == other.client;
}
};
class CToplevelExportProtocolManager {
public:
CToplevelExportProtocolManager();
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, CWindow* handle);
void removeClient(SToplevelClient* client, bool force = false);
void removeFrame(SToplevelFrame* frame, bool force = false);
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
void onMonitorRender(CMonitor* pMonitor);
void displayDestroy();
void onWindowUnmap(CWindow* pWindow);
private:
wl_global* m_pGlobal = nullptr;
std::list<SToplevelFrame> m_lFrames;
std::list<SToplevelClient> m_lClients;
wl_listener m_liDisplayDestroy;
std::vector<SToplevelFrame*> m_vFramesAwaitingWrite;
void shareFrame(SToplevelFrame* frame);
bool copyFrameDmabuf(SToplevelFrame* frame);
bool copyFrameShm(SToplevelFrame* frame, timespec* now);
};

View File

@@ -0,0 +1,312 @@
#include <GLES2/gl2ext.h>
struct wlr_pixel_format_info {
uint32_t drm_format;
/* Equivalent of the format if it has an alpha channel,
* DRM_FORMAT_INVALID (0) if NA
*/
uint32_t opaque_substitute;
/* Bits per pixels */
uint32_t bpp;
/* True if the format has an alpha channel */
bool has_alpha;
};
static const struct wlr_pixel_format_info pixel_format_info[] = {
{
.drm_format = DRM_FORMAT_XRGB8888,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 32,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ARGB8888,
.opaque_substitute = DRM_FORMAT_XRGB8888,
.bpp = 32,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR8888,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 32,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ABGR8888,
.opaque_substitute = DRM_FORMAT_XBGR8888,
.bpp = 32,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGBX8888,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 32,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_RGBA8888,
.opaque_substitute = DRM_FORMAT_RGBX8888,
.bpp = 32,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_BGRX8888,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 32,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_BGRA8888,
.opaque_substitute = DRM_FORMAT_BGRX8888,
.bpp = 32,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_BGR888,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 24,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_RGBX4444,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 16,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_RGBA4444,
.opaque_substitute = DRM_FORMAT_RGBX4444,
.bpp = 16,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGBX5551,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 16,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_RGBA5551,
.opaque_substitute = DRM_FORMAT_RGBX5551,
.bpp = 16,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGB565,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 16,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_BGR565,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 16,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_XRGB2101010,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 32,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ARGB2101010,
.opaque_substitute = DRM_FORMAT_XRGB2101010,
.bpp = 32,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR2101010,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 32,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ABGR2101010,
.opaque_substitute = DRM_FORMAT_XBGR2101010,
.bpp = 32,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR16161616F,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 64,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ABGR16161616F,
.opaque_substitute = DRM_FORMAT_XBGR16161616F,
.bpp = 64,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR16161616,
.opaque_substitute = DRM_FORMAT_INVALID,
.bpp = 64,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ABGR16161616,
.opaque_substitute = DRM_FORMAT_XBGR16161616,
.bpp = 64,
.has_alpha = true,
},
};
static const size_t pixel_format_info_size =
sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fmt) {
for (size_t i = 0; i < pixel_format_info_size; ++i) {
if (pixel_format_info[i].drm_format == fmt) {
return &pixel_format_info[i];
}
}
return NULL;
}
uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
switch (fmt) {
case WL_SHM_FORMAT_XRGB8888:
return DRM_FORMAT_XRGB8888;
case WL_SHM_FORMAT_ARGB8888:
return DRM_FORMAT_ARGB8888;
default:
return (uint32_t)fmt;
}
}
enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
switch (fmt) {
case DRM_FORMAT_XRGB8888:
return WL_SHM_FORMAT_XRGB8888;
case DRM_FORMAT_ARGB8888:
return WL_SHM_FORMAT_ARGB8888;
default:
return (enum wl_shm_format)fmt;
}
}
struct wlr_gles2_pixel_format {
uint32_t drm_format;
// optional field, if empty then internalformat = format
GLint gl_internalformat;
GLint gl_format, gl_type;
bool has_alpha;
};
static const struct wlr_gles2_pixel_format formats[] = {
{
.drm_format = DRM_FORMAT_ARGB8888,
.gl_format = GL_BGRA_EXT,
.gl_type = GL_UNSIGNED_BYTE,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XRGB8888,
.gl_format = GL_BGRA_EXT,
.gl_type = GL_UNSIGNED_BYTE,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_XBGR8888,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_BYTE,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ABGR8888,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_BYTE,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_BGR888,
.gl_format = GL_RGB,
.gl_type = GL_UNSIGNED_BYTE,
.has_alpha = false,
},
#if WLR_LITTLE_ENDIAN
{
.drm_format = DRM_FORMAT_RGBX4444,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_SHORT_4_4_4_4,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_RGBA4444,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_SHORT_4_4_4_4,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGBX5551,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_SHORT_5_5_5_1,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_RGBA5551,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_SHORT_5_5_5_1,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_RGB565,
.gl_format = GL_RGB,
.gl_type = GL_UNSIGNED_SHORT_5_6_5,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_XBGR2101010,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ABGR2101010,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR16161616F,
.gl_format = GL_RGBA,
.gl_type = GL_HALF_FLOAT_OES,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ABGR16161616F,
.gl_format = GL_RGBA,
.gl_type = GL_HALF_FLOAT_OES,
.has_alpha = true,
},
{
.drm_format = DRM_FORMAT_XBGR16161616,
.gl_internalformat = GL_RGBA16_EXT,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_SHORT,
.has_alpha = false,
},
{
.drm_format = DRM_FORMAT_ABGR16161616,
.gl_internalformat = GL_RGBA16_EXT,
.gl_format = GL_RGBA,
.gl_type = GL_UNSIGNED_SHORT,
.has_alpha = true,
},
#endif
};
const struct wlr_gles2_pixel_format* get_gles2_format_from_drm(uint32_t fmt) {
for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) {
if (formats[i].drm_format == fmt) {
return &formats[i];
}
}
return NULL;
}

View File

@@ -27,7 +27,6 @@ bool CFramebuffer::alloc(int w, int h) {
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0);
// TODO: Allow this with gles2 // TODO: Allow this with gles2
#ifndef GLES2 #ifndef GLES2
if (m_pStencilTex) { if (m_pStencilTex) {
@@ -74,8 +73,13 @@ void CFramebuffer::release() {
m_cTex.m_iTexID = 0; m_cTex.m_iTexID = 0;
m_iFb = -1; m_iFb = -1;
m_Size = Vector2D();
} }
CFramebuffer::~CFramebuffer() { CFramebuffer::~CFramebuffer() {
release(); release();
} }
bool CFramebuffer::isAllocated() {
return m_iFb != (GLuint)-1;
}

View File

@@ -12,6 +12,7 @@ public:
void bind(); void bind();
void release(); void release();
void reset(); void reset();
bool isAllocated();
Vector2D m_Position; Vector2D m_Position;
Vector2D m_Size; Vector2D m_Size;

View File

@@ -1,3 +1,4 @@
#include "Shaders.hpp"
#include "OpenGL.hpp" #include "OpenGL.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
@@ -24,23 +25,27 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!"); Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!");
#endif #endif
// End shaders
pixman_region32_init(&m_rOriginalDamageRegion); pixman_region32_init(&m_rOriginalDamageRegion);
// End
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
// Done!
} }
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag) { GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag, bool dynamic) {
auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert); auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert, dynamic);
RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n%s", vert.c_str()); if (dynamic) {
if (vertCompiled == 0)
return 0;
} else {
RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n%s", vert.c_str());
}
auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag); auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag, dynamic);
RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n%s", frag.c_str()); if (dynamic) {
if (fragCompiled == 0)
return 0;
} else {
RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n%s", frag.c_str());
}
auto prog = glCreateProgram(); auto prog = glCreateProgram();
glAttachShader(prog, vertCompiled); glAttachShader(prog, vertCompiled);
@@ -54,12 +59,17 @@ GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string
GLint ok; GLint ok;
glGetProgramiv(prog, GL_LINK_STATUS, &ok); glGetProgramiv(prog, GL_LINK_STATUS, &ok);
RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!"); if (dynamic) {
if (ok == GL_FALSE)
return 0;
} else {
RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!");
}
return prog; return prog;
} }
GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) { GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool dynamic) {
auto shader = glCreateShader(type); auto shader = glCreateShader(type);
auto shaderSource = src.c_str(); auto shaderSource = src.c_str();
@@ -69,7 +79,12 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) {
GLint ok; GLint ok;
glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!"); if (dynamic) {
if (ok == GL_FALSE)
return 0;
} else {
RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!");
}
return shader; return shader;
} }
@@ -117,6 +132,11 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool
m_RenderData.pDamage = pDamage; m_RenderData.pDamage = pDamage;
m_bFakeFrame = fake; m_bFakeFrame = fake;
if (m_bReloadScreenShader) {
m_bReloadScreenShader = false;
applyScreenShader(g_pConfigManager->getString("decoration:screen_shader"));
}
} }
void CHyprOpenGLImpl::end() { void CHyprOpenGLImpl::end() {
@@ -133,9 +153,11 @@ void CHyprOpenGLImpl::end() {
clear(CColor(11, 11, 11, 255)); clear(CColor(11, 11, 11, 255));
m_bEndFrame = true; m_bEndFrame = true;
m_bApplyFinalShader = true;
renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 255.f, 0); renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 255.f, 0);
m_bApplyFinalShader = false;
m_bEndFrame = false; m_bEndFrame = false;
} }
@@ -150,9 +172,7 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj");
m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color"); m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color");
m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shQUAD.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shQUAD.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius"); m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shQUAD.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample"); m_RenderData.pCurrentMonData->m_shQUAD.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
@@ -166,7 +186,6 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shRGBA.posAttrib = glGetAttribLocation(prog, "pos"); m_RenderData.pCurrentMonData->m_shRGBA.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shRGBA.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); m_RenderData.pCurrentMonData->m_shRGBA.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_RenderData.pCurrentMonData->m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shRGBA.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shRGBA.radius = glGetUniformLocation(prog, "radius"); m_RenderData.pCurrentMonData->m_shRGBA.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shRGBA.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample"); m_RenderData.pCurrentMonData->m_shRGBA.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
@@ -182,7 +201,6 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shRGBX.posAttrib = glGetAttribLocation(prog, "pos"); m_RenderData.pCurrentMonData->m_shRGBX.posAttrib = glGetAttribLocation(prog, "pos");
m_RenderData.pCurrentMonData->m_shRGBX.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); m_RenderData.pCurrentMonData->m_shRGBX.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_RenderData.pCurrentMonData->m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shRGBX.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shRGBX.radius = glGetUniformLocation(prog, "radius"); m_RenderData.pCurrentMonData->m_shRGBX.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shRGBX.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample"); m_RenderData.pCurrentMonData->m_shRGBX.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
@@ -198,7 +216,6 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord"); m_RenderData.pCurrentMonData->m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shEXT.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); m_RenderData.pCurrentMonData->m_shEXT.discardOpaque = glGetUniformLocation(prog, "discardOpaque");
m_RenderData.pCurrentMonData->m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shEXT.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shEXT.radius = glGetUniformLocation(prog, "radius"); m_RenderData.pCurrentMonData->m_shEXT.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shEXT.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample"); m_RenderData.pCurrentMonData->m_shEXT.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
@@ -247,15 +264,48 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shBORDER1.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shBORDER1.topLeft = glGetUniformLocation(prog, "topLeft");
m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight = glGetUniformLocation(prog, "bottomRight"); m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight = glGetUniformLocation(prog, "bottomRight");
m_RenderData.pCurrentMonData->m_shBORDER1.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shBORDER1.fullSize = glGetUniformLocation(prog, "fullSize");
m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed = glGetUniformLocation(prog, "fullSizeUntransformed");
m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius"); m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius");
m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample"); m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample = glGetUniformLocation(prog, "primitiveMultisample");
m_RenderData.pCurrentMonData->m_shBORDER1.color = glGetUniformLocation(prog, "color"); m_RenderData.pCurrentMonData->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient");
m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength");
m_RenderData.pCurrentMonData->m_shBORDER1.angle = glGetUniformLocation(prog, "angle");
m_RenderData.pCurrentMonData->m_shBORDER1.alpha = glGetUniformLocation(prog, "alpha");
m_RenderData.pCurrentMonData->m_bShadersInitialized = true; m_RenderData.pCurrentMonData->m_bShadersInitialized = true;
Debug::log(LOG, "Shaders initialized successfully."); Debug::log(LOG, "Shaders initialized successfully.");
} }
void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
m_sFinalScreenShader.destroy();
if (path == "" || path == STRVAL_EMPTY)
return;
std::ifstream infile(absolutePath(path, std::string(getenv("HOME")) + "/.config/hypr"));
if (!infile.good()) {
g_pConfigManager->addParseError("Screen shader parser: Screen shader path not found");
return;
}
std::string fragmentShader((std::istreambuf_iterator<char>(infile)), (std::istreambuf_iterator<char>()));
m_sFinalScreenShader.program = createProgram(TEXVERTSRC, fragmentShader, true);
if (!m_sFinalScreenShader.program) {
g_pConfigManager->addParseError("Screen shader parser: Screen shader parse failed");
return;
}
m_sFinalScreenShader.proj = glGetUniformLocation(m_sFinalScreenShader.program, "proj");
m_sFinalScreenShader.tex = glGetUniformLocation(m_sFinalScreenShader.program, "tex");
m_sFinalScreenShader.texAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "texcoord");
m_sFinalScreenShader.posAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "pos");
}
void CHyprOpenGLImpl::clear(const CColor& color) { void CHyprOpenGLImpl::clear(const CColor& color) {
RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!");
@@ -314,7 +364,8 @@ void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h
} }
void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col, int round) { void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col, int round) {
renderRectWithDamage(box, col, m_RenderData.pDamage, round); if(pixman_region32_not_empty(m_RenderData.pDamage))
renderRectWithDamage(box, col, m_RenderData.pDamage, round);
} }
void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixman_region32_t* damage, int round) { void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixman_region32_t* damage, int round) {
@@ -326,27 +377,31 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
wlr_matrix_transpose(glMatrix, glMatrix);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program); glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix);
#else
wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f); glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
const auto TOPLEFT = Vector2D(round, round); wlr_box transformedBox;
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round); wlr_box_transform(&transformedBox, box, wlr_output_transform_invert(m_RenderData.pMonitor->transform),
const auto FULLSIZE = Vector2D(box->width, box->height); m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y);
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
// Rounded corners // Rounded corners
glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.radius, round);
glUniform1i(m_RenderData.pCurrentMonData->m_shQUAD.primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0)); glUniform1i(m_RenderData.pCurrentMonData->m_shQUAD.primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0));
@@ -357,12 +412,26 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.texAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.texAttrib);
if (pixman_region32_not_empty(damage)) { if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) {
PIXMAN_DAMAGE_FOREACH(damage) { pixman_region32_t damageClip;
const auto RECT = RECTSARR[i]; pixman_region32_init(&damageClip);
scissor(&RECT); pixman_region32_intersect_rect(&damageClip, damage, m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (pixman_region32_not_empty(&damageClip)) {
PIXMAN_DAMAGE_FOREACH(&damageClip) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} }
pixman_region32_fini(&damageClip);
} else {
PIXMAN_DAMAGE_FOREACH(damage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} }
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib); glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib);
@@ -389,6 +458,9 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
if (!pixman_region32_not_empty(m_RenderData.pDamage))
return;
static auto *const PDIMINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:dim_inactive")->intValue; static auto *const PDIMINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:dim_inactive")->intValue;
// get transform // get transform
@@ -398,27 +470,31 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
wlr_matrix_transpose(glMatrix, glMatrix);
CShader* shader = nullptr; CShader* shader = nullptr;
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
switch (tex.m_iType) { bool usingFinalShader = false;
case TEXTURE_RGBA:
shader = &m_RenderData.pCurrentMonData->m_shRGBA; if (m_bApplyFinalShader && m_sFinalScreenShader.program) {
break; shader = &m_sFinalScreenShader;
case TEXTURE_RGBX: usingFinalShader = true;
shader = &m_RenderData.pCurrentMonData->m_shRGBX; } else {
break; switch (tex.m_iType) {
case TEXTURE_EXTERNAL: case TEXTURE_RGBA:
shader = &m_RenderData.pCurrentMonData->m_shEXT; shader = &m_RenderData.pCurrentMonData->m_shRGBA;
break; break;
default: case TEXTURE_RGBX:
RASSERT(false, "tex.m_iTarget unsupported!"); shader = &m_RenderData.pCurrentMonData->m_shRGBX;
break;
case TEXTURE_EXTERNAL:
shader = &m_RenderData.pCurrentMonData->m_shEXT;
break;
default:
RASSERT(false, "tex.m_iTarget unsupported!");
}
} }
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
@@ -428,32 +504,40 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
glUseProgram(shader->program); glUseProgram(shader->program);
#ifndef GLES2
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix);
#else
wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1i(shader->tex, 0); glUniform1i(shader->tex, 0);
glUniform1f(shader->alpha, alpha / 255.f); if (!usingFinalShader) {
glUniform1i(shader->discardOpaque, (int)discardOpaque); glUniform1f(shader->alpha, alpha / 255.f);
glUniform1i(shader->discardOpaque, (int)discardOpaque);
}
// round is in px wlr_box transformedBox;
// so we need to do some maf wlr_box_transform(&transformedBox, pBox, wlr_output_transform_invert(m_RenderData.pMonitor->transform),
m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y);
const auto TOPLEFT = Vector2D(round, round); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
const auto BOTTOMRIGHT = Vector2D(pBox->width - round, pBox->height - round); const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
const auto FULLSIZE = Vector2D(pBox->width, pBox->height);
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
// Rounded corners if (!usingFinalShader) {
glUniform2f(shader->topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); // Rounded corners
glUniform2f(shader->bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y);
glUniform2f(shader->fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y);
glUniform1f(shader->radius, round); glUniform1f(shader->radius, round);
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA)); glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) { if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) {
glUniform1i(shader->applyTint, 1); glUniform1i(shader->applyTint, 1);
const auto DIM = m_pCurrentWindow->m_fDimPercent.fl(); const auto DIM = m_pCurrentWindow->m_fDimPercent.fl();
glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM);
} else { } else {
glUniform1i(shader->applyTint, 0); glUniform1i(shader->applyTint, 0);
}
} }
const float verts[] = { const float verts[] = {
@@ -474,12 +558,26 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
glEnableVertexAttribArray(shader->posAttrib); glEnableVertexAttribArray(shader->posAttrib);
glEnableVertexAttribArray(shader->texAttrib); glEnableVertexAttribArray(shader->texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) { if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { pixman_region32_t damageClip;
const auto RECT = RECTSARR[i]; pixman_region32_init(&damageClip);
scissor(&RECT); pixman_region32_intersect_rect(&damageClip, damage, m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (pixman_region32_not_empty(&damageClip)) {
PIXMAN_DAMAGE_FOREACH(&damageClip) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} }
pixman_region32_fini(&damageClip);
} else {
PIXMAN_DAMAGE_FOREACH(damage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} }
glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->posAttrib);
@@ -505,8 +603,6 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
wlr_matrix_transpose(glMatrix, glMatrix);
// get the config settings // get the config settings
static auto *const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue; static auto *const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
@@ -541,7 +637,12 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
glUseProgram(pShader->program); glUseProgram(pShader->program);
// prep two shaders // prep two shaders
#ifndef GLES2
glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix);
#else
wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
#endif
glUniform1f(pShader->radius, *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a glUniform1f(pShader->radius, *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a
if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1)
glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f));
@@ -614,14 +715,16 @@ void CHyprOpenGLImpl::markBlurDirtyForMonitor(CMonitor* pMonitor) {
void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) {
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue; static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
static auto *const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue;
static auto *const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
if (!*PBLURNEWOPTIMIZE || !m_mMonitorRenderResources[pMonitor].blurFBDirty) if (!*PBLURNEWOPTIMIZE || !m_mMonitorRenderResources[pMonitor].blurFBDirty || !*PBLUR)
return; return;
bool has = false; bool has = false;
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pMonitor->activeWorkspace && w->m_bIsMapped && !w->m_bHidden && !w->m_bIsFloating) { if (w->m_iWorkspaceID == pMonitor->activeWorkspace && w->m_bIsMapped && !w->isHidden() && (!w->m_bIsFloating || *PBLURXRAY)) {
has = true; has = true;
break; break;
} }
@@ -649,6 +752,8 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
renderTextureInternalWithDamage(POUTFB->m_cTex, &wholeMonitor, 255, &fakeDamage, 0, false, true, false); renderTextureInternalWithDamage(POUTFB->m_cTex, &wholeMonitor, 255, &fakeDamage, 0, false, true, false);
m_bEndFrame = false; m_bEndFrame = false;
pixman_region32_fini(&fakeDamage);
m_RenderData.pCurrentMonData->primaryFB.bind(); m_RenderData.pCurrentMonData->primaryFB.bind();
m_RenderData.pCurrentMonData->blurFBDirty = false; m_RenderData.pCurrentMonData->blurFBDirty = false;
@@ -656,13 +761,54 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() {
void CHyprOpenGLImpl::preWindowPass() { void CHyprOpenGLImpl::preWindowPass() {
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue; static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
static auto *const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue;
static auto *const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
if (!m_RenderData.pCurrentMonData->blurFBDirty || !*PBLURNEWOPTIMIZE) if (!m_RenderData.pCurrentMonData->blurFBDirty || !*PBLURNEWOPTIMIZE || !*PBLUR)
return; return;
auto windowShouldBeBlurred = [&] (CWindow* pWindow) -> bool {
if (!pWindow)
return false;
if (pWindow->m_sAdditionalConfigData.forceNoBlur)
return false;
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
if (PSURFACE->opaque)
return false;
pixman_region32_t inverseOpaque;
pixman_region32_init(&inverseOpaque);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
const float A = pWindow->m_fAlpha.fl() * pWindow->m_fActiveInactiveAlpha.fl() * PWORKSPACE->m_fAlpha.fl() / 255.f;
if (A >= 255.f) {
pixman_box32_t surfbox = {0, 0, PSURFACE->current.width, PSURFACE->current.height};
pixman_region32_copy(&inverseOpaque, &PSURFACE->current.opaque);
pixman_region32_inverse(&inverseOpaque, &inverseOpaque, &surfbox);
pixman_region32_intersect_rect(&inverseOpaque, &inverseOpaque, 0, 0, PSURFACE->current.width, PSURFACE->current.height);
if (!pixman_region32_not_empty(&inverseOpaque)) {
pixman_region32_fini(&inverseOpaque);
return false;
}
}
pixman_region32_fini(&inverseOpaque);
return true;
};
bool hasWindows = false; bool hasWindows = false;
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == m_RenderData.pMonitor->activeWorkspace && !w->m_bHidden && w->m_bIsMapped && !w->m_bIsFloating) { if (w->m_iWorkspaceID == m_RenderData.pMonitor->activeWorkspace && !w->isHidden() && w->m_bIsMapped && (!w->m_bIsFloating || *PBLURXRAY)) {
// check if window is valid
if (!windowShouldBeBlurred(w.get()))
continue;
hasWindows = true; hasWindows = true;
break; break;
} }
@@ -675,45 +821,64 @@ void CHyprOpenGLImpl::preWindowPass() {
preBlurForCurrentMonitor(); preBlurForCurrentMonitor();
} }
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round) { void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round, bool blockBlurOptimization) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!");
static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue; static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
static auto *const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue; static auto *const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue;
static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue; static auto *const PBLURNEWOPTIMIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_new_optimizations")->intValue;
static auto *const PBLURXRAY = &g_pConfigManager->getConfigValuePtr("decoration:blur_xray")->intValue;
if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) {
renderTexture(tex, pBox, a, round, false, true);
return;
}
// make a damage region for this window // make a damage region for this window
pixman_region32_t damage; pixman_region32_t damage;
pixman_region32_init(&damage); pixman_region32_init(&damage);
pixman_region32_intersect_rect(&damage, m_RenderData.pDamage, pBox->x, pBox->y, pBox->width, pBox->height); // clip it to the box pixman_region32_intersect_rect(&damage, m_RenderData.pDamage, pBox->x, pBox->y, pBox->width, pBox->height); // clip it to the box
// amazing hack: the surface has an opaque region! if(!pixman_region32_not_empty(&damage))
pixman_region32_t inverseOpaque; return;
pixman_region32_init(&inverseOpaque);
if (a == 255.f) {
pixman_box32_t monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
pixman_region32_copy(&inverseOpaque, &pSurface->current.opaque);
pixman_region32_translate(&inverseOpaque, pBox->x, pBox->y);
pixman_region32_inverse(&inverseOpaque, &inverseOpaque, &monbox);
pixman_region32_intersect(&inverseOpaque, &damage, &inverseOpaque);
} else {
pixman_region32_copy(&inverseOpaque, &damage);
}
if (!pixman_region32_not_empty(&inverseOpaque)) { if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) {
renderTexture(tex, pBox, a, round, false, true); // reject blurring a fully opaque window renderTexture(tex, pBox, a, round, false, true);
return; return;
} }
// vvv TODO: layered blur fbs? // amazing hack: the surface has an opaque region!
const bool USENEWOPTIMIZE = (*PBLURNEWOPTIMIZE && m_pCurrentWindow && !m_pCurrentWindow->m_bIsFloating && m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID && m_pCurrentWindow->m_iWorkspaceID != SPECIAL_WORKSPACE_ID); pixman_region32_t inverseOpaque;
pixman_region32_init(&inverseOpaque);
if (a >= 255.f) {
pixman_box32_t surfbox = {0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale};
pixman_region32_copy(&inverseOpaque, &pSurface->current.opaque);
pixman_region32_inverse(&inverseOpaque, &inverseOpaque, &surfbox);
pixman_region32_intersect_rect(&inverseOpaque, &inverseOpaque, 0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale);
const auto POUTFB = USENEWOPTIMIZE ? &m_RenderData.pCurrentMonData->blurFB : blurMainFramebufferWithDamage(a, pBox, &inverseOpaque); if (!pixman_region32_not_empty(&inverseOpaque)) {
pixman_region32_fini(&inverseOpaque);
renderTexture(tex, pBox, a, round, false, true);
return;
}
} else {
pixman_region32_init_rect(&inverseOpaque, 0, 0, pBox->width, pBox->height);
}
// vvv TODO: layered blur fbs?
const bool USENEWOPTIMIZE = (*PBLURNEWOPTIMIZE && !blockBlurOptimization && ((m_pCurrentWindow && !m_pCurrentWindow->m_bIsFloating) || *PBLURXRAY) && m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID && (!m_pCurrentWindow || !g_pCompositor->isWorkspaceSpecial(m_pCurrentWindow->m_iWorkspaceID) ));
CFramebuffer* POUTFB = nullptr;
if (!USENEWOPTIMIZE) {
if (pSurface->current.scale != 1) {
// wlroots prohibits shrinking a region
// TODO: just shrink
pixman_region32_union_rect(&inverseOpaque, &inverseOpaque, 0, 0, pBox->width, pBox->height);
}
pixman_region32_translate(&inverseOpaque, pBox->x, pBox->y);
pixman_region32_intersect(&inverseOpaque, &inverseOpaque, &damage);
POUTFB = blurMainFramebufferWithDamage(a, pBox, &inverseOpaque);
} else {
POUTFB = &m_RenderData.pCurrentMonData->blurFB;
}
pixman_region32_fini(&inverseOpaque); pixman_region32_fini(&inverseOpaque);
@@ -742,21 +907,19 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
// stencil done. Render everything. // stencil done. Render everything.
wlr_box MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; wlr_box MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
if (pixman_region32_not_empty(&damage)) { // render our great blurred FB
// render our great blurred FB static auto *const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue;
static auto *const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue; m_bEndFrame = true; // fix transformed
m_bEndFrame = true; // fix transformed renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, false);
renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, false); m_bEndFrame = false;
m_bEndFrame = false;
// render the window, but clear stencil // render the window, but clear stencil
glClearStencil(0); glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT); glClear(GL_STENCIL_BUFFER_BIT);
// draw window // draw window
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true, true); renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true, true);
}
glStencilMask(-1); glStencilMask(-1);
glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilFunc(GL_ALWAYS, 1, 0xFF);
@@ -771,10 +934,13 @@ void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) {
counter++; counter++;
} }
void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) { void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CGradientValueData& grad, int round, float a) {
RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!");
RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!");
if (!pixman_region32_not_empty(m_RenderData.pDamage) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBorder))
return;
static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto *const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; static auto *const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
@@ -783,52 +949,49 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
int scaledBorderSize = *PBORDERSIZE * m_RenderData.pMonitor->scale; int scaledBorderSize = *PBORDERSIZE * m_RenderData.pMonitor->scale;
if (round < 1) {
// zero rounding, just lines
wlr_box borderbox = {box->x - scaledBorderSize, box->y - scaledBorderSize, scaledBorderSize, box->height + 2 * scaledBorderSize};
renderRect(&borderbox, col, 0); // left
borderbox = {box->x, box->y - (int)scaledBorderSize, box->width + (int)scaledBorderSize, (int)scaledBorderSize};
renderRect(&borderbox, col, 0); // top
borderbox = {box->x + box->width, box->y, (int)scaledBorderSize, box->height + (int)scaledBorderSize};
renderRect(&borderbox, col, 0); // right
borderbox = {box->x, box->y + box->height, box->width, (int)scaledBorderSize};
renderRect(&borderbox, col, 0); // bottom
return;
}
// adjust box // adjust box
box->x -= scaledBorderSize; box->x -= scaledBorderSize;
box->y -= scaledBorderSize; box->y -= scaledBorderSize;
box->width += 2 * scaledBorderSize; box->width += 2 * scaledBorderSize;
box->height += 2 * scaledBorderSize; box->height += 2 * scaledBorderSize;
round += scaledBorderSize; round += round == 0 ? 0 : scaledBorderSize;
float matrix[9]; 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 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
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
wlr_matrix_transpose(glMatrix, glMatrix);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program); glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix);
#else
wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
glUniform4f(m_RenderData.pCurrentMonData->m_shBORDER1.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f); #endif
const auto TOPLEFT = Vector2D(round, round); static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round);
const auto FULLSIZE = Vector2D(box->width, box->height); glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad.m_vColors.size(), (float*)grad.m_vColors.data());
glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad.m_vColors.size());
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle, (int)(grad.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0));
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a);
wlr_box transformedBox;
wlr_box_transform(&transformedBox, box, wlr_output_transform_invert(m_RenderData.pMonitor->transform),
m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y);
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height);
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round);
glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize);
glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample, *PMULTISAMPLE); glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.primitiveMultisample, *PMULTISAMPLE);
@@ -839,18 +1002,93 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) { if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { pixman_region32_t damageClip;
const auto RECT = RECTSARR[i]; pixman_region32_init(&damageClip);
scissor(&RECT); pixman_region32_intersect_rect(&damageClip, m_RenderData.pDamage, m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (pixman_region32_not_empty(&damageClip)) {
PIXMAN_DAMAGE_FOREACH(&damageClip) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} }
pixman_region32_fini(&damageClip);
} else {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} }
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib); glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib);
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib); glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// fix back box
box->x += scaledBorderSize;
box->y += scaledBorderSize;
box->width -= 2 * scaledBorderSize;
box->height -= 2 * scaledBorderSize;
}
void CHyprOpenGLImpl::makeRawWindowSnapshot(CWindow* pWindow, CFramebuffer* pFramebuffer) {
// we trust the window is valid.
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
wlr_output_attach_render(PMONITOR->output, nullptr);
// we need to "damage" the entire monitor
// so that we render the entire window
// 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->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
begin(PMONITOR, &fakeDamage, true);
clear(CColor(0, 0, 0, 0)); // JIC
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
// this is a hack but it works :P
// we need to disable blur or else we will get a black background, as the shader
// will try to copy the bg to apply blur.
// this isn't entirely correct, but like, oh well.
// small todo: maybe make this correct? :P
const auto BLURVAL = g_pConfigManager->getInt("decoration:blur");
g_pConfigManager->setInt("decoration:blur", 0);
// TODO: how can we make this the size of the window? setting it to window's size makes the entire screen render with the wrong res forever more. odd.
glViewport(0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
pFramebuffer->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
pFramebuffer->bind();
clear(CColor(0, 0, 0, 0)); // JIC
g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, false, RENDER_PASS_ALL, true);
g_pConfigManager->setInt("decoration:blur", BLURVAL);
// restore original fb
#ifndef GLES2
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb);
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
#endif
end();
pixman_region32_fini(&fakeDamage);
wlr_output_rollback(PMONITOR->output);
} }
void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
@@ -867,7 +1105,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
begin(PMONITOR, &fakeDamage, true); begin(PMONITOR, &fakeDamage, true);
clear(CColor(0,0,0,0)); // JIC clear(CColor(0, 0, 0, 0)); // JIC
timespec now; timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
@@ -880,10 +1118,9 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
const auto BLURVAL = g_pConfigManager->getInt("decoration:blur"); const auto BLURVAL = g_pConfigManager->getInt("decoration:blur");
g_pConfigManager->setInt("decoration:blur", 0); g_pConfigManager->setInt("decoration:blur", 0);
// render onto the window fb glViewport(0, 0, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y);
const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y); const auto PFRAMEBUFFER = &m_mWindowFramebuffers[pWindow];
PFRAMEBUFFER->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; PFRAMEBUFFER->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
@@ -897,12 +1134,12 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
g_pConfigManager->setInt("decoration:blur", BLURVAL); g_pConfigManager->setInt("decoration:blur", BLURVAL);
// restore original fb // restore original fb
#ifndef GLES2 #ifndef GLES2
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_iCurrentOutputFb);
#else #else
glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb); glBindFramebuffer(GL_FRAMEBUFFER, m_iCurrentOutputFb);
#endif #endif
end(); end();
pixman_region32_fini(&fakeDamage); pixman_region32_fini(&fakeDamage);
@@ -937,9 +1174,14 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
timespec now; timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
const auto BLURLSSTATUS = pLayer->forceBlur;
pLayer->forceBlur = false;
// draw the layer // draw the layer
g_pHyprRenderer->renderLayer(pLayer, PMONITOR, &now); g_pHyprRenderer->renderLayer(pLayer, PMONITOR, &now);
pLayer->forceBlur = BLURLSSTATUS;
// TODO: WARN: // TODO: WARN:
// revise if any stencil-requiring rendering is done to the layers. // revise if any stencil-requiring rendering is done to the layers.
@@ -957,6 +1199,14 @@ void CHyprOpenGLImpl::makeLayerSnapshot(SLayerSurface* pLayer) {
wlr_output_rollback(PMONITOR->output); wlr_output_rollback(PMONITOR->output);
} }
void CHyprOpenGLImpl::onWindowResizeStart(CWindow* pWindow) {
}
void CHyprOpenGLImpl::onWindowResizeEnd(CWindow* pWindow) {
}
void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) { void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) {
RASSERT(m_RenderData.pMonitor, "Tried to render snapshot rect without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render snapshot rect without begin()!");
const auto PWINDOW = *pWindow; const auto PWINDOW = *pWindow;
@@ -1040,6 +1290,9 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
RASSERT((box->width > 0 && box->height > 0), "Tried to render shadow with width/height < 0!"); 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!"); RASSERT(m_pCurrentWindow, "Tried to render shadow without a window!");
if (!pixman_region32_not_empty(m_RenderData.pDamage))
return;
static auto *const PSHADOWPOWER = &g_pConfigManager->getConfigValuePtr("decoration:shadow_render_power")->intValue; static auto *const PSHADOWPOWER = &g_pConfigManager->getConfigValuePtr("decoration:shadow_render_power")->intValue;
const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4); const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4);
@@ -1051,16 +1304,18 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
float glMatrix[9]; float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
wlr_matrix_transpose(glMatrix, glMatrix);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program); glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program);
#ifndef GLES2
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix);
#else
wlr_matrix_transpose(glMatrix, glMatrix);
glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix);
#endif
glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a); glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a);
const auto TOPLEFT = Vector2D(range + round, range + round); const auto TOPLEFT = Vector2D(range + round, range + round);
@@ -1081,12 +1336,26 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib);
glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib); glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) { if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { pixman_region32_t damageClip;
const auto RECT = RECTSARR[i]; pixman_region32_init(&damageClip);
scissor(&RECT); pixman_region32_intersect_rect(&damageClip, m_RenderData.pDamage, m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (pixman_region32_not_empty(&damageClip)) {
PIXMAN_DAMAGE_FOREACH(&damageClip) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} }
pixman_region32_fini(&damageClip);
} else {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
} }
glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib); glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib);
@@ -1225,17 +1494,32 @@ void CHyprOpenGLImpl::clearWithTex() {
static auto *const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue; static auto *const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
if (!*PRENDERTEX) { if (!*PRENDERTEX) {
renderTexture(m_mMonitorBGTextures[m_RenderData.pMonitor], &m_mMonitorRenderResources[m_RenderData.pMonitor].backgroundTexBox, 255, 0); auto TEXIT = m_mMonitorBGTextures.find(m_RenderData.pMonitor);
if (TEXIT == m_mMonitorBGTextures.end()) {
createBGTextureForMonitor(m_RenderData.pMonitor);
TEXIT = m_mMonitorBGTextures.find(m_RenderData.pMonitor);
}
if (TEXIT != m_mMonitorBGTextures.end())
renderTexture(TEXIT->second, &m_mMonitorRenderResources[m_RenderData.pMonitor].backgroundTexBox, 255, 0);
} }
} }
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
wlr_output_attach_render(pMonitor->output, nullptr);
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorFB.release(); g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].primaryFB.release(); g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].primaryFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].mirrorSwapFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].monitorMirrorFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].blurFB.release();
g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].stencilTex.destroyTexture(); g_pHyprOpenGL->m_mMonitorRenderResources[pMonitor].stencilTex.destroyTexture();
g_pHyprOpenGL->m_mMonitorBGTextures[pMonitor].destroyTexture(); g_pHyprOpenGL->m_mMonitorBGTextures[pMonitor].destroyTexture();
g_pHyprOpenGL->m_mMonitorRenderResources.erase(pMonitor); g_pHyprOpenGL->m_mMonitorRenderResources.erase(pMonitor);
g_pHyprOpenGL->m_mMonitorBGTextures.erase(pMonitor); g_pHyprOpenGL->m_mMonitorBGTextures.erase(pMonitor);
Debug::log(LOG, "Monitor %s -> destroyed all render data", pMonitor->szName.c_str()); Debug::log(LOG, "Monitor %s -> destroyed all render data", pMonitor->szName.c_str());
wlr_output_rollback(pMonitor->output);
} }

View File

@@ -12,11 +12,8 @@
#include "Texture.hpp" #include "Texture.hpp"
#include "Framebuffer.hpp" #include "Framebuffer.hpp"
inline const float matrixFlip180[] = { class CHyprRenderer;
1.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
};
inline const float fullVerts[] = { inline const float fullVerts[] = {
1, 0, // top right 1, 0, // top right
0, 0, // top left 0, 0, // top left
@@ -67,8 +64,12 @@ struct SCurrentRenderData {
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
wlr_box clipBox = {};
}; };
class CGradientValueData;
class CHyprOpenGLImpl { class CHyprOpenGLImpl {
public: public:
@@ -81,11 +82,12 @@ public:
void renderRectWithDamage(wlr_box*, const CColor&, pixman_region32_t* damage, int round = 0); void renderRectWithDamage(wlr_box*, const CColor&, pixman_region32_t* damage, int round = 0);
void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0, bool allowCustomUV = false); void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0, bool allowCustomUV = false);
void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowCustomUV = false); void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowCustomUV = false);
void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0); void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false);
void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0); void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0);
void renderBorder(wlr_box*, const CColor&, int round); void renderBorder(wlr_box*, const CGradientValueData&, int round, float a = 1.0);
void makeWindowSnapshot(CWindow*); void makeWindowSnapshot(CWindow*);
void makeRawWindowSnapshot(CWindow*, CFramebuffer*);
void makeLayerSnapshot(SLayerSurface*); void makeLayerSnapshot(SLayerSurface*);
void renderSnapshot(CWindow**); void renderSnapshot(CWindow**);
void renderSnapshot(SLayerSurface**); void renderSnapshot(SLayerSurface**);
@@ -106,11 +108,18 @@ public:
void saveBufferForMirror(); void saveBufferForMirror();
void renderMirrored(); void renderMirrored();
void onWindowResizeStart(CWindow*);
void onWindowResizeEnd(CWindow*);
void applyScreenShader(const std::string& path);
SCurrentRenderData m_RenderData; SCurrentRenderData m_RenderData;
GLint m_iCurrentOutputFb = 0; GLint m_iCurrentOutputFb = 0;
GLint m_iWLROutputFb = 0; GLint m_iWLROutputFb = 0;
bool m_bReloadScreenShader = true; // at launch it can be set
CWindow* m_pCurrentWindow = nullptr; // hack to get the current rendered window CWindow* m_pCurrentWindow = nullptr; // hack to get the current rendered window
pixman_region32_t m_rOriginalDamageRegion; // used for storing the pre-expanded region pixman_region32_t m_rOriginalDamageRegion; // used for storing the pre-expanded region
@@ -129,9 +138,12 @@ private:
bool m_bFakeFrame = false; bool m_bFakeFrame = false;
bool m_bEndFrame = false; bool m_bEndFrame = false;
bool m_bApplyFinalShader = false;
GLuint createProgram(const std::string&, const std::string&); CShader m_sFinalScreenShader;
GLuint compileShader(const GLuint&, std::string);
GLuint createProgram(const std::string&, const std::string&, bool dynamic = false);
GLuint compileShader(const GLuint&, std::string, bool dynamic = false);
void createBGTextureForMonitor(CMonitor*); void createBGTextureForMonitor(CMonitor*);
void initShaders(); void initShaders();
@@ -142,6 +154,8 @@ private:
void renderSplash(cairo_t *const, cairo_surface_t *const, double); void renderSplash(cairo_t *const, cairo_surface_t *const, double);
void preBlurForCurrentMonitor(); void preBlurForCurrentMonitor();
friend class CHyprRenderer;
}; };
inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL; inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL;

View File

@@ -1,5 +1,6 @@
#include "Renderer.hpp" #include "Renderer.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "linux-dmabuf-unstable-v1-protocol.h"
void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
const auto TEXTURE = wlr_surface_get_texture(surface); const auto TEXTURE = wlr_surface_get_texture(surface);
@@ -41,7 +42,7 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true); g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
} else { } else {
if (RDATA->blur) if (RDATA->blur)
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding); g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, RDATA->blockBlurOptimization);
else else
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true); g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
} }
@@ -50,9 +51,10 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true); g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
} }
wlr_surface_send_frame_done(surface, RDATA->when); if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
wlr_surface_send_frame_done(surface, RDATA->when);
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output); wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output);
}
// reset the UV, we might've set it above // reset the UV, we might've set it above
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
@@ -84,12 +86,10 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
return true; return true;
// if not, check if it maybe is active on a different monitor. // if not, check if it maybe is active on a different monitor.
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) || if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) && pWindow->m_bIsFloating /* tiled windows can't be multi-ws */)
(PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && PWORKSPACE->m_bForceRendering) || // vvvv might be in animation progress vvvvv
(PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
return !pWindow->m_bIsFullscreen; // Do not draw fullscreen windows on other monitors return !pWindow->m_bIsFullscreen; // Do not draw fullscreen windows on other monitors
if (pMonitor->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (pMonitor->specialWorkspaceID == pWindow->m_iWorkspaceID)
return true; return true;
return false; return false;
@@ -112,7 +112,7 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) {
if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))
return true; return true;
if (m->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (m->specialWorkspaceID && g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
return true; return true;
} }
@@ -169,6 +169,12 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
pWorkspaceWindow = w.get(); pWorkspaceWindow = w.get();
} }
if (!pWorkspaceWindow) {
// ?? happens sometimes...
pWorkspace->m_bHasFullscreenWindow = false;
return; // this will produce one blank frame. Oh well.
}
// then render windows over fullscreen. // then render windows over fullscreen.
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || !w->m_bIsMapped) if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || !w->m_bIsMapped)
@@ -178,11 +184,11 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
} }
// and then special windows // and then special windows
for (auto& w : g_pCompositor->m_vWindows) { if (pMonitor->specialWorkspaceID) for (auto& w : g_pCompositor->m_vWindows) {
if (!g_pCompositor->windowValidMapped(w.get()) && !w->m_bFadingOut) if (!g_pCompositor->windowValidMapped(w.get()) && !w->m_bFadingOut)
continue; continue;
if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) if (w->m_iWorkspaceID != pMonitor->specialWorkspaceID)
continue; continue;
if (!shouldRenderWindow(w.get(), pMonitor)) if (!shouldRenderWindow(w.get(), pMonitor))
@@ -210,8 +216,8 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
g_pHyprError->draw(); g_pHyprError->draw();
} }
void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode) { void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool ignoreAllGeometry) {
if (pWindow->m_bHidden) if (pWindow->isHidden())
return; return;
if (pWindow->m_bFadingOut) { if (pWindow->m_bFadingOut) {
@@ -222,9 +228,17 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
const auto REALPOS = pWindow->m_vRealPosition.vec() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset.vec()); const auto REALPOS = pWindow->m_vRealPosition.vec() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset.vec());
static const auto PNOFLOATINGBORDERS = &g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue; static auto *const PNOFLOATINGBORDERS = &g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue;
SRenderData renderdata = {pMonitor->output, time, REALPOS.x, REALPOS.y}; SRenderData renderdata = {pMonitor->output, time, REALPOS.x, REALPOS.y};
if (ignorePosition) {
renderdata.x = pMonitor->vecPosition.x;
renderdata.y = pMonitor->vecPosition.y;
}
if (ignoreAllGeometry)
decorate = false;
renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow); renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow);
renderdata.w = std::max(pWindow->m_vRealSize.vec().x, 5.0); // clamp the size to min 5, renderdata.w = std::max(pWindow->m_vRealSize.vec().x, 5.0); // clamp the size to min 5,
renderdata.h = std::max(pWindow->m_vRealSize.vec().y, 5.0); // otherwise we'll have issues later with invalid boxes renderdata.h = std::max(pWindow->m_vRealSize.vec().y, 5.0); // otherwise we'll have issues later with invalid boxes
@@ -232,15 +246,14 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (pWindow->m_bPinned ? 1.f : (PWORKSPACE->m_fAlpha.fl() / 255.f)); renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (pWindow->m_bPinned ? 1.f : (PWORKSPACE->m_fAlpha.fl() / 255.f));
renderdata.alpha = pWindow->m_fActiveInactiveAlpha.fl(); renderdata.alpha = pWindow->m_fActiveInactiveAlpha.fl();
renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true) && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL); 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.rounding = ignoreAllGeometry ? 0 : pWindow->m_sAdditionalConfigData.rounding;
renderdata.blur = true; // if it shouldn't, it will be ignored later renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later
renderdata.pWindow = pWindow; renderdata.pWindow = pWindow;
// apply window special data if (ignoreAllGeometry) {
if (pWindow->m_sSpecialRenderData.alphaInactive == -1) renderdata.alpha = 1.f;
renderdata.alpha *= pWindow->m_sSpecialRenderData.alpha; renderdata.fadeAlpha = 255.f;
else }
renderdata.alpha *= pWindow == g_pCompositor->m_pLastWindow ? pWindow->m_sSpecialRenderData.alpha : pWindow->m_sSpecialRenderData.alphaInactive;
// apply opaque // apply opaque
if (pWindow->m_sAdditionalConfigData.forceOpaque) if (pWindow->m_sAdditionalConfigData.forceOpaque)
@@ -248,11 +261,39 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
g_pHyprOpenGL->m_pCurrentWindow = pWindow; g_pHyprOpenGL->m_pCurrentWindow = pWindow;
// render window decorations first, if not fullscreen full // clip box for animated offsets
Vector2D offset;
if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bPinned) {
if (PWORKSPACE->m_vRenderOffset.vec().x != 0) {
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().x / PWSMON->vecSize.x;
const auto WINBB = pWindow->getFullWindowBoundingBox();
if (WINBB.x < PWSMON->vecPosition.x) {
offset.x = (PWSMON->vecPosition.x - WINBB.x) * PROGRESS;
} else if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x) {
offset.x = (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS;
}
} else if (PWORKSPACE->m_vRenderOffset.vec().y) {
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.vec().y / PWSMON->vecSize.y;
const auto WINBB = pWindow->getFullWindowBoundingBox();
if (WINBB.y < PWSMON->vecPosition.y) {
offset.y = (PWSMON->vecPosition.y - WINBB.y) * PROGRESS;
} else if (WINBB.y + WINBB.height > PWSMON->vecPosition.y + PWSMON->vecSize.y) {
offset.y = (WINBB.y + WINBB.width - PWSMON->vecPosition.y - PWSMON->vecSize.y) * PROGRESS;
}
}
renderdata.x += offset.x;
renderdata.y += offset.y;
}
// render window decorations first, if not fullscreen full
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_MAIN) { if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_MAIN) {
if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) for (auto& wd : pWindow->m_dWindowDecorations) if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) for (auto& wd : pWindow->m_dWindowDecorations)
wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f); wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f, offset);
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata); wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
@@ -262,14 +303,20 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding; float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding;
rounding *= pMonitor->scale; rounding *= pMonitor->scale;
auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col(); auto grad = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor;
col.a *= renderdata.fadeAlpha * renderdata.alpha / 255.f; const bool ANIMATED = g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAnimationProgress.isBeingAnimated();
float a1 = renderdata.fadeAlpha * renderdata.alpha / 255.f * (ANIMATED ? g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAnimationProgress.fl() : 1.f);
wlr_box windowBox = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h}; wlr_box windowBox = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h};
scaleBox(&windowBox, pMonitor->scale); scaleBox(&windowBox, pMonitor->scale);
g_pHyprOpenGL->renderBorder(&windowBox, col, rounding); g_pHyprOpenGL->renderBorder(&windowBox, grad, rounding, a1);
if (ANIMATED) {
float a2 = renderdata.fadeAlpha * renderdata.alpha / 255.f * (1.f - g_pHyprOpenGL->m_pCurrentWindow->m_fBorderAnimationProgress.fl());
g_pHyprOpenGL->renderBorder(&windowBox, g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColorPrevious, rounding, a2);
}
} }
} }
@@ -289,6 +336,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
} }
g_pHyprOpenGL->m_pCurrentWindow = nullptr; g_pHyprOpenGL->m_pCurrentWindow = nullptr;
g_pHyprOpenGL->m_RenderData.clipBox = { 0, 0, 0, 0 };
} }
void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, timespec* time) { void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, timespec* time) {
@@ -304,6 +352,7 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times
renderdata.decorate = false; renderdata.decorate = false;
renderdata.w = pLayer->layerSurface->surface->current.width; renderdata.w = pLayer->layerSurface->surface->current.width;
renderdata.h = pLayer->layerSurface->surface->current.height; renderdata.h = pLayer->layerSurface->surface->current.height;
renderdata.blockBlurOptimization = pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM || pLayer->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND;
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata); wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
renderdata.squishOversized = false; // don't squish popups renderdata.squishOversized = false; // don't squish popups
@@ -349,33 +398,44 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
return; return;
} }
CWindow* lastWindow = nullptr;
// Non-floating main // Non-floating main
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
continue; continue;
if (w->m_bIsFloating) if (w->m_bIsFloating)
continue; // floating are in the second pass continue; // floating are in the second pass
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue; // special are in the third pass continue; // special are in the third pass
if (!shouldRenderWindow(w.get(), PMONITOR)) if (!shouldRenderWindow(w.get(), PMONITOR))
continue; continue;
// render active window after all others of this pass
if (w.get() == g_pCompositor->m_pLastWindow) {
lastWindow = w.get();
continue;
}
// render the bad boy // render the bad boy
renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_MAIN); renderWindow(w.get(), PMONITOR, time, true, RENDER_PASS_MAIN);
} }
if (lastWindow)
renderWindow(lastWindow, PMONITOR, time, true, RENDER_PASS_MAIN);
// Non-floating popup // Non-floating popup
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
continue; continue;
if (w->m_bIsFloating) if (w->m_bIsFloating)
continue; // floating are in the second pass continue; // floating are in the second pass
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue; // special are in the third pass continue; // special are in the third pass
if (!shouldRenderWindow(w.get(), PMONITOR)) if (!shouldRenderWindow(w.get(), PMONITOR))
@@ -387,13 +447,13 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
// floating on top // floating on top
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
continue; continue;
if (!w->m_bIsFloating) if (!w->m_bIsFloating)
continue; continue;
if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue; continue;
if (!shouldRenderWindow(w.get(), PMONITOR)) if (!shouldRenderWindow(w.get(), PMONITOR))
@@ -405,10 +465,10 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
// and then special // and then special
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut)
continue; continue;
if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) if (!g_pCompositor->isWorkspaceSpecial(w->m_iWorkspaceID))
continue; continue;
if (!shouldRenderWindow(w.get(), PMONITOR)) if (!shouldRenderWindow(w.get(), PMONITOR))
@@ -501,6 +561,154 @@ void CHyprRenderer::calculateUVForWindowSurface(CWindow* pWindow, wlr_surface* p
} }
} }
void countSubsurfacesIter(wlr_surface* pSurface, int x, int y, void* data) {
*(int*)data += 1;
}
bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
if (!pMonitor->mirrors.empty())
return false; // do not DS if this monitor is being mirrored. Will break the functionality.
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace);
if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || g_pCompositor->m_sSeat.exclusiveClient || pMonitor->specialWorkspaceID)
return false;
const auto PCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
if (!PCANDIDATE)
return false; // ????
if (PCANDIDATE->m_fAlpha.fl() != 255.f || PCANDIDATE->m_fActiveInactiveAlpha.fl() != 1.f || PWORKSPACE->m_fAlpha.fl() != 255.f)
return false;
if (PCANDIDATE->m_vRealSize.vec() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition.vec() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition.isBeingAnimated() || PCANDIDATE->m_vRealSize.isBeingAnimated())
return false;
if (!pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty())
return false;
for (auto& topls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
if (topls->alpha.fl() != 0.f)
return false;
}
// check if it did not open any subsurfaces or shit
int surfaceCount = 0;
if (PCANDIDATE->m_bIsX11) {
surfaceCount = 1;
// check opaque
if (PCANDIDATE->m_uSurface.xwayland->has_alpha)
return false;
} else {
wlr_xdg_surface_for_each_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
wlr_xdg_surface_for_each_popup_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
if (!PCANDIDATE->m_uSurface.xdg->surface->opaque)
return false;
}
if (surfaceCount != 1)
return false;
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
return false;
// finally, we should be GTG.
wlr_output_attach_buffer(pMonitor->output, &PSURFACE->buffer->base);
if (!wlr_output_test(pMonitor->output)) {
return false;
}
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_surface_send_frame_done(PSURFACE, &now);
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, PSURFACE, pMonitor->output);
if (wlr_output_commit(pMonitor->output)) {
if (!m_pLastScanout) {
m_pLastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to %x: \"%s\"", PCANDIDATE, PCANDIDATE->m_szTitle.c_str());
}
} else {
m_pLastScanout = nullptr;
return false;
}
return true;
}
void CHyprRenderer::setWindowScanoutMode(CWindow* pWindow) {
if (!g_pCompositor->m_sWLRLinuxDMABuf)
return;
if (!pWindow->m_bIsFullscreen) {
wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, g_pXWaylandManager->getWindowSurface(pWindow), nullptr);
Debug::log(LOG, "Scanout mode OFF set for %x", pWindow);
return;
}
const auto RENDERERDRMFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
const auto BACKENDDRMFD = wlr_backend_get_drm_fd(g_pCompositor->m_sWLRBackend);
if (RENDERERDRMFD < 0 || BACKENDDRMFD < 0)
return;
auto deviceIDFromFD = [](int fd, unsigned long* deviceID) -> bool {
struct stat stat;
if (fstat(fd, &stat) != 0) {
return false;
}
*deviceID = stat.st_rdev;
return true;
};
unsigned long rendererDevice, scanoutDevice;
if (!deviceIDFromFD(RENDERERDRMFD, &rendererDevice) || !deviceIDFromFD(BACKENDDRMFD, &scanoutDevice))
return;
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto POUTPUTFORMATS = wlr_output_get_primary_formats(PMONITOR->output, WLR_BUFFER_CAP_DMABUF);
if (!POUTPUTFORMATS)
return;
const auto PRENDERERFORMATS = wlr_renderer_get_dmabuf_texture_formats(g_pCompositor->m_sWLRRenderer);
wlr_drm_format_set scanoutFormats = { 0 };
if (!wlr_drm_format_set_intersect(&scanoutFormats, POUTPUTFORMATS, PRENDERERFORMATS))
return;
const wlr_linux_dmabuf_feedback_v1_tranche TRANCHES[] = {
{
.target_device = scanoutDevice,
.flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT,
.formats = &scanoutFormats
}, {
.target_device = rendererDevice,
.formats = PRENDERERFORMATS
}
};
const wlr_linux_dmabuf_feedback_v1 FEEDBACK = {
.main_device = rendererDevice,
.tranches_len = sizeof(TRANCHES) / sizeof(TRANCHES[0]),
.tranches = TRANCHES
};
if (!wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, g_pXWaylandManager->getWindowSurface(pWindow), &FEEDBACK)) {
Debug::log(ERR, "Error in scanout mode setting: wlr_linux_dmabuf_v1_set_surface_feedback returned false.");
}
wlr_drm_format_set_finish(&scanoutFormats);
Debug::log(LOG, "Scanout mode ON set for %x", pWindow);
}
void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool test) { void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool test) {
wlr_output_configuration_head_v1* head; wlr_output_configuration_head_v1* head;
bool noError = true; bool noError = true;
@@ -528,9 +736,17 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
commandForCfg += std::to_string(head->state.x) + "x" + std::to_string(head->state.y) + "," + std::to_string(head->state.scale); commandForCfg += std::to_string(head->state.x) + "x" + std::to_string(head->state.y) + "," + std::to_string(head->state.scale);
if (!test) if (!test) {
g_pConfigManager->parseKeyword("monitor", commandForCfg, true); g_pConfigManager->parseKeyword("monitor", commandForCfg, true);
std::string transformStr = std::string(OUTPUT->name) + ",transform," + std::to_string((int)OUTPUT->transform);
const auto PMONITOR = g_pCompositor->getMonitorFromName(OUTPUT->name);
if (!PMONITOR || OUTPUT->transform != PMONITOR->transform)
g_pConfigManager->parseKeyword("monitor", transformStr);
}
noError = wlr_output_test(OUTPUT); noError = wlr_output_test(OUTPUT);
if (!noError) if (!noError)
@@ -728,9 +944,15 @@ void CHyprRenderer::arrangeLayersForMonitor(const int& monitor) {
PMONITOR->vecReservedTopLeft = Vector2D(usableArea.x, usableArea.y) - PMONITOR->vecPosition; PMONITOR->vecReservedTopLeft = Vector2D(usableArea.x, usableArea.y) - PMONITOR->vecPosition;
PMONITOR->vecReservedBottomRight = PMONITOR->vecSize - Vector2D(usableArea.width, usableArea.height) - PMONITOR->vecReservedTopLeft; PMONITOR->vecReservedBottomRight = PMONITOR->vecSize - Vector2D(usableArea.width, usableArea.height) - PMONITOR->vecReservedTopLeft;
const auto ENTRY = g_pConfigManager->m_mAdditionalReservedAreas[PMONITOR->szName]; auto ADDITIONALRESERVED = g_pConfigManager->m_mAdditionalReservedAreas.find(PMONITOR->szName);
PMONITOR->vecReservedTopLeft = PMONITOR->vecReservedTopLeft + Vector2D(ENTRY.left, ENTRY.top); if (ADDITIONALRESERVED == g_pConfigManager->m_mAdditionalReservedAreas.end()) {
PMONITOR->vecReservedBottomRight = PMONITOR->vecReservedBottomRight + Vector2D(ENTRY.right, ENTRY.bottom); ADDITIONALRESERVED = g_pConfigManager->m_mAdditionalReservedAreas.find(""); // glob wildcard
}
if (ADDITIONALRESERVED != g_pConfigManager->m_mAdditionalReservedAreas.end()) {
PMONITOR->vecReservedTopLeft = PMONITOR->vecReservedTopLeft + Vector2D(ADDITIONALRESERVED->second.left, ADDITIONALRESERVED->second.top);
PMONITOR->vecReservedBottomRight = PMONITOR->vecReservedBottomRight + Vector2D(ADDITIONALRESERVED->second.right, ADDITIONALRESERVED->second.bottom);
}
// damage the monitor if can // damage the monitor if can
if (PMONITOR->damage) if (PMONITOR->damage)
@@ -808,7 +1030,7 @@ void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
if (g_pCompositor->m_bUnsafeState || pMonitor->isMirror()) if (g_pCompositor->m_bUnsafeState || pMonitor->isMirror())
return; return;
wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y}; wlr_box damageBox = { 0, 0, INT16_MAX, INT16_MAX };
pMonitor->addDamage(&damageBox); pMonitor->addDamage(&damageBox);
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
@@ -912,7 +1134,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
&& DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1) && DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1)
&& pMonitor->scale == pMonitorRule->scale && pMonitor->scale == pMonitorRule->scale
&& ((DELTALESSTHAN(pMonitor->vecPosition.x, pMonitorRule->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, pMonitorRule->offset.y, 1)) || pMonitorRule->offset == Vector2D(-1, -1)) && ((DELTALESSTHAN(pMonitor->vecPosition.x, pMonitorRule->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, pMonitorRule->offset.y, 1)) || pMonitorRule->offset == Vector2D(-1, -1))
&& pMonitor->transform == pMonitorRule->transform) { && pMonitor->transform == pMonitorRule->transform
&& pMonitorRule->enable10bit == pMonitor->enabled10bit) {
Debug::log(LOG, "Not applying a new rule to %s because it's already applied!", pMonitor->szName.c_str()); Debug::log(LOG, "Not applying a new rule to %s because it's already applied!", pMonitor->szName.c_str());
return true; return true;
@@ -921,7 +1144,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
wlr_output_set_scale(pMonitor->output, pMonitorRule->scale); wlr_output_set_scale(pMonitor->output, pMonitorRule->scale);
pMonitor->scale = pMonitorRule->scale; pMonitor->scale = pMonitorRule->scale;
pMonitor->vecPosition = pMonitorRule->offset; wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
pMonitor->transform = pMonitorRule->transform;
// loop over modes and choose an appropriate one. // loop over modes and choose an appropriate one.
if (pMonitorRule->resolution != Vector2D() && pMonitorRule->resolution != Vector2D(-1,-1) && pMonitorRule->resolution != Vector2D(-1,-2)) { if (pMonitorRule->resolution != Vector2D() && pMonitorRule->resolution != Vector2D(-1,-1) && pMonitorRule->resolution != Vector2D(-1,-2)) {
@@ -1117,26 +1341,37 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
} }
pMonitor->vrrActive = pMonitor->output->pending.adaptive_sync_enabled; // disabled here, will be tested in CConfigManager::ensureVRR()
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
pMonitor->transform = pMonitorRule->transform;
pMonitor->vecPixelSize = pMonitor->vecSize; pMonitor->vecPixelSize = pMonitor->vecSize;
// Adaptive sync (VRR) if (pMonitorRule->enable10bit) {
wlr_output_enable_adaptive_sync(pMonitor->output, 1); // try 10b RGB
wlr_output_set_render_format(pMonitor->output, DRM_FORMAT_XRGB2101010);
pMonitor->enabled10bit = true;
if (!wlr_output_test(pMonitor->output)) { if (!wlr_output_test(pMonitor->output)) {
Debug::log(LOG, "Pending output %s does not accept VRR.", pMonitor->output->name); Debug::log(ERR, "Output %s -> 10 bit enabled, but failed format DRM_FORMAT_XRGB2101010. Trying BGR.", pMonitor->output->name);
wlr_output_enable_adaptive_sync(pMonitor->output, 0);
wlr_output_set_render_format(pMonitor->output, DRM_FORMAT_XBGR2101010);
if (!wlr_output_test(pMonitor->output)) {
Debug::log(ERR, "Output %s -> 10 bit enabled, but failed format DRM_FORMAT_XBGR2101010. Falling back to 8 bit.", pMonitor->output->name);
wlr_output_set_render_format(pMonitor->output, DRM_FORMAT_XRGB8888);
} else {
Debug::log(LOG, "10bit format DRM_FORMAT_XBGR2101010 succeeded for output %s", pMonitor->output->name);
}
} else {
Debug::log(LOG, "10bit format DRM_FORMAT_XRGB2101010 succeeded for output %s", pMonitor->output->name);
}
} else {
wlr_output_set_render_format(pMonitor->output, DRM_FORMAT_XRGB8888);
pMonitor->enabled10bit = false;
} }
// update renderer
g_pHyprOpenGL->destroyMonitorResources(pMonitor);
if (!wlr_output_commit(pMonitor->output)) { if (!wlr_output_commit(pMonitor->output)) {
Debug::log(ERR, "Couldn't commit output named %s", pMonitor->output->name); Debug::log(ERR, "Couldn't commit output named %s", pMonitor->output->name);
return true;
} }
int x, y; int x, y;
@@ -1144,7 +1379,14 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor(); pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor();
pMonitor->vecTransformedSize = Vector2D(x,y); pMonitor->vecTransformedSize = Vector2D(x,y);
if (pMonitorRule->offset == Vector2D(-1, -1)) { if (pMonitor->createdByUser) {
wlr_box transformedBox = { 0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y };
wlr_box_transform(&transformedBox, &transformedBox, wlr_output_transform_invert(pMonitor->output->transform), (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height);
}
if (pMonitorRule->offset == Vector2D(-1, -1) && pMonitor->vecPosition == Vector2D(-1, -1)) {
// let's find manually a sensible position for it, to the right. // let's find manually a sensible position for it, to the right.
Vector2D finalPos; Vector2D finalPos;
@@ -1158,15 +1400,15 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
pMonitor->vecPosition = finalPos; pMonitor->vecPosition = finalPos;
} else if (pMonitorRule->offset != Vector2D(-1, -1)) {
pMonitor->vecPosition = pMonitorRule->offset;
} }
if (!pMonitor->isMirror()) // update renderer (here because it will call rollback, so we cannot do this before committing)
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y); g_pHyprOpenGL->destroyMonitorResources(pMonitor);
wlr_output_enable(pMonitor->output, true);
// updato wlroots // updato wlroots
Events::listener_change(nullptr, nullptr); wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y);
// updato us // updato us
arrangeLayersForMonitor(pMonitor->ID); arrangeLayersForMonitor(pMonitor->ID);

View File

@@ -23,6 +23,8 @@ enum eRenderPassMode {
RENDER_PASS_POPUP RENDER_PASS_POPUP
}; };
class CToplevelExportProtocolManager;
class CHyprRenderer { class CHyprRenderer {
public: public:
@@ -44,13 +46,18 @@ public:
void calculateUVForWindowSurface(CWindow*, wlr_surface*, bool main = false); void calculateUVForWindowSurface(CWindow*, wlr_surface*, bool main = false);
bool m_bWindowRequestedCursorHide = false; bool m_bWindowRequestedCursorHide = false;
bool m_bBlockSurfaceFeedback = false;
CWindow* m_pLastScanout = nullptr;
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
bool attemptDirectScanout(CMonitor*);
void setWindowScanoutMode(CWindow*);
private: private:
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*); void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
void renderWorkspaceWithFullscreenWindow(CMonitor*, CWorkspace*, timespec*); void renderWorkspaceWithFullscreenWindow(CMonitor*, CWorkspace*, timespec*);
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode); void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false);
void renderLayer(SLayerSurface*, CMonitor*, timespec*); void renderLayer(SLayerSurface*, CMonitor*, timespec*);
void renderDragIcon(CMonitor*, timespec*); void renderDragIcon(CMonitor*, timespec*);
void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*); void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*);
@@ -59,6 +66,7 @@ private:
friend class CHyprOpenGLImpl; friend class CHyprOpenGLImpl;
friend class CToplevelExportProtocolManager;
}; };
inline std::unique_ptr<CHyprRenderer> g_pHyprRenderer; inline std::unique_ptr<CHyprRenderer> g_pHyprRenderer;

View File

@@ -14,7 +14,11 @@ GLint CShader::getUniformLocation(const std::string& unif) {
CShader::~CShader() { CShader::~CShader() {
// destroy shader // destroy shader
if (program) { destroy();
glDeleteProgram(program); }
}
void CShader::destroy() {
glDeleteProgram(program);
program = 0;
} }

View File

@@ -19,6 +19,7 @@ public:
GLint topLeft; GLint topLeft;
GLint bottomRight; GLint bottomRight;
GLint fullSize; GLint fullSize;
GLint fullSizeUntransformed;
GLint radius; GLint radius;
GLint primitiveMultisample; GLint primitiveMultisample;
@@ -32,8 +33,14 @@ public:
GLint applyTint; GLint applyTint;
GLint tint; GLint tint;
GLint gradient;
GLint gradientLength;
GLint angle;
GLint getUniformLocation(const std::string&); GLint getUniformLocation(const std::string&);
void destroy();
private: private:
std::unordered_map<std::string, GLint> m_muUniforms; std::unordered_map<std::string, GLint> m_muUniforms;
}; };

View File

@@ -48,7 +48,7 @@ void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) {
} }
} }
void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) { void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
if (!g_pCompositor->windowValidMapped(m_pWindow)) if (!g_pCompositor->windowValidMapped(m_pWindow))
return; return;
@@ -59,10 +59,14 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) {
if (!m_pWindow->m_sSpecialRenderData.decorate) if (!m_pWindow->m_sSpecialRenderData.decorate)
return; return;
if (m_pWindow->m_sAdditionalConfigData.forceNoShadow)
return;
static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; 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 PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue;
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue; static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
static auto *const PSHADOWSCALE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_scale")->floatValue;
static auto *const PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->vecValue; static auto *const PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->vecValue;
if (*PSHADOWS != 1) if (*PSHADOWS != 1)
@@ -70,19 +74,48 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) {
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ? 0 : (m_pWindow->m_sAdditionalConfigData.rounding == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding); const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ? 0 : (m_pWindow->m_sAdditionalConfigData.rounding == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding);
// update the extents
m_seExtents = {{*PSHADOWSIZE + 2 - PSHADOWOFFSET->x, *PSHADOWSIZE + 2 - PSHADOWOFFSET->y}, {*PSHADOWSIZE + 2 + PSHADOWOFFSET->x, *PSHADOWSIZE + 2 + PSHADOWOFFSET->y}};
// draw the shadow // draw the shadow
wlr_box fullBox = {m_vLastWindowPos.x - m_seExtents.topLeft.x + 2, m_vLastWindowPos.y - m_seExtents.topLeft.y + 2, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x - 4, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y - 4}; wlr_box fullBox = { m_vLastWindowPos.x - *PSHADOWSIZE, m_vLastWindowPos.y - *PSHADOWSIZE,
m_vLastWindowSize.x + 2.0 * *PSHADOWSIZE, m_vLastWindowSize.y + 2.0 * *PSHADOWSIZE };
fullBox.x -= pMonitor->vecPosition.x; fullBox.x -= pMonitor->vecPosition.x;
fullBox.y -= pMonitor->vecPosition.y; fullBox.y -= pMonitor->vecPosition.y;
if (fullBox.width < 1 || fullBox.height < 1) const float SHADOWSCALE = std::clamp(*PSHADOWSCALE, 0.f, 1.f);
return; // don't draw invisible shadows
g_pHyprOpenGL->scissor((wlr_box *)nullptr); // scale the box in relation to the center of the box
const Vector2D NEWSIZE = Vector2D { fullBox.width, fullBox.height } * SHADOWSCALE;
fullBox.width = NEWSIZE.x;
fullBox.height = NEWSIZE.y;
if (PSHADOWOFFSET->x < 0) {
fullBox.x += PSHADOWOFFSET->x;
} else if (PSHADOWOFFSET->x > 0) {
fullBox.x = m_vLastWindowPos.x + m_vLastWindowSize.x - fullBox.width + (SHADOWSCALE * *PSHADOWSIZE) + PSHADOWOFFSET->x - pMonitor->vecPosition.x;
} else {
fullBox.x += ((m_vLastWindowSize.x + 2.0 * *PSHADOWSIZE) - NEWSIZE.x) / 2.0;
}
if (PSHADOWOFFSET->y < 0) {
fullBox.y += PSHADOWOFFSET->y;
} else if (PSHADOWOFFSET->y > 0) {
fullBox.y = m_vLastWindowPos.y + m_vLastWindowSize.y - fullBox.height + (SHADOWSCALE * *PSHADOWSIZE) + PSHADOWOFFSET->y - pMonitor->vecPosition.y;
} else {
fullBox.y += ((m_vLastWindowSize.y + 2.0 * *PSHADOWSIZE) - NEWSIZE.y) / 2.0;
}
m_seExtents = { { m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2,
m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2},
{ fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2,
fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2} };
fullBox.x += offset.x;
fullBox.y += offset.y;
if (fullBox.width < 1 || fullBox.height < 1)
return; // don't draw invisible shadows
g_pHyprOpenGL->scissor((wlr_box*)nullptr);
if (*PSHADOWIGNOREWINDOW) { if (*PSHADOWIGNOREWINDOW) {
glEnable(GL_STENCIL_TEST); glEnable(GL_STENCIL_TEST);

View File

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

View File

@@ -63,11 +63,11 @@ void CHyprGroupBarDecoration::damageEntire() {
g_pHyprRenderer->damageBox(&dm); g_pHyprRenderer->damageBox(&dm);
} }
void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
// get how many bars we will draw // get how many bars we will draw
int barsToDraw = m_dwGroupMembers.size(); int barsToDraw = m_dwGroupMembers.size();
if (barsToDraw < 1 || m_pWindow->m_bHidden || !g_pCompositor->windowValidMapped(m_pWindow)) if (barsToDraw < 1 || m_pWindow->isHidden() || !g_pCompositor->windowValidMapped(m_pWindow))
return; return;
if (!m_pWindow->m_sSpecialRenderData.decorate) if (!m_pWindow->m_sSpecialRenderData.decorate)
@@ -80,7 +80,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) {
int xoff = 0; int xoff = 0;
for (int i = 0; i < barsToDraw; ++i) { for (int i = 0; i < barsToDraw; ++i) {
wlr_box rect = {m_vLastWindowPos.x + xoff - pMonitor->vecPosition.x, m_vLastWindowPos.y - m_seExtents.topLeft.y - pMonitor->vecPosition.y, BARW, 3}; wlr_box rect = {m_vLastWindowPos.x + xoff - pMonitor->vecPosition.x + offset.x, m_vLastWindowPos.y - m_seExtents.topLeft.y - pMonitor->vecPosition.y + offset.y, BARW, 3};
if (rect.width <= 0 || rect.height <= 0) if (rect.width <= 0 || rect.height <= 0)
break; break;

View File

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

View File

@@ -22,7 +22,7 @@ public:
virtual SWindowDecorationExtents getWindowDecorationExtents() = 0; virtual SWindowDecorationExtents getWindowDecorationExtents() = 0;
virtual void draw(CMonitor*, float a) = 0; virtual void draw(CMonitor*, float a, const Vector2D& offset = Vector2D()) = 0;
virtual eDecorationType getDecorationType() = 0; virtual eDecorationType getDecorationType() = 0;

View File

@@ -9,82 +9,111 @@ varying vec4 v_color;
varying vec2 v_texcoord; varying vec2 v_texcoord;
uniform vec2 topLeft; uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize; uniform vec2 fullSize;
uniform vec2 fullSizeUntransformed;
uniform float radius; uniform float radius;
uniform float thick; uniform float thick;
uniform int primitiveMultisample; uniform int primitiveMultisample;
float getOpacityForPixAndCorner(vec2 pix, vec2 corner) { uniform vec4 gradient[10];
uniform int gradientLength;
uniform float angle;
uniform float alpha;
if (primitiveMultisample == 0) { vec4 getColorForCoord(vec2 normalizedCoord) {
float dis = distance(pix + vec2(0.5, 0.5), corner); if (gradientLength < 2)
return dis < radius && dis > radius - thick ? 1.0 : 0.0; return gradient[0];
float finalAng = 0.0;
if (angle > 4.71 /* 270 deg */) {
normalizedCoord[1] = 1.0 - normalizedCoord[1];
finalAng = 6.28 - angle;
} else if (angle > 3.14 /* 180 deg */) {
normalizedCoord[0] = 1.0 - normalizedCoord[0];
normalizedCoord[1] = 1.0 - normalizedCoord[1];
finalAng = angle - 3.14;
} else if (angle > 1.57 /* 90 deg */) {
normalizedCoord[0] = 1.0 - normalizedCoord[0];
finalAng = 3.14 - angle;
} else {
finalAng = angle;
} }
float distance1 = distance(pix + vec2(0.25, 0.25), corner); float sine = sin(finalAng);
float distance2 = distance(pix + vec2(0.75, 0.25), corner);
float distance3 = distance(pix + vec2(0.25, 0.75), corner);
float distance4 = distance(pix + vec2(0.75, 0.75), corner);
float v1 = distance1 < radius && distance1 > radius - thick ? 1.0 : 0.0; float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradientLength - 1);
float v2 = distance2 < radius && distance2 > radius - thick ? 1.0 : 0.0; int bottom = int(floor(progress));
float v3 = distance3 < radius && distance3 > radius - thick ? 1.0 : 0.0; int top = bottom + 1;
float v4 = distance4 < radius && distance4 > radius - thick ? 1.0 : 0.0;
return (v1 + v2 + v3 + v4) / 4.0; return gradient[top] * (progress - float(bottom)) + gradient[bottom] * (float(top) - progress);
} }
void main() { void main() {
vec2 pixCoord = fullSize * v_texcoord; highp vec2 pixCoord = vec2(gl_FragCoord);
highp vec2 originalPixCoord = v_texcoord;
originalPixCoord *= fullSizeUntransformed;
vec4 pixColor = v_color; vec4 pixColor = vec4(1.0, 1.0, 1.0, 1.0);
bool done = false; bool done = false;
// check for edges pixCoord -= topLeft + fullSize * 0.5;
if (pixCoord[0] < topLeft[0]) { pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
if (pixCoord[1] < topLeft[1]) { pixCoord -= fullSize * 0.5 - radius;
// top left
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, topLeft + vec2(1,1)); if (min(pixCoord.x, pixCoord.y) > 0.0 && radius > 0.0) {
done = true;
} else if (pixCoord[1] > bottomRight[1]) { float dist = length(pixCoord);
// bottom left
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(topLeft[0] + 1.0, bottomRight[1])); if (dist > radius + 1.0 || dist < radius - thick - 1.0)
done = true; discard;
}
} else if (pixCoord[0] > bottomRight[0]) { if (primitiveMultisample == 1 && (dist > radius - 1.0 || dist < radius - thick + 1.0)) {
if (pixCoord[1] < topLeft[1]) { float distances = 0.0;
// top right float len = length(pixCoord + vec2(0.25, 0.25));
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(bottomRight[0], topLeft[1] + 1.0)); distances += float(len < radius && len > radius - thick);
done = true; len = length(pixCoord + vec2(0.75, 0.25));
} else if (pixCoord[1] > bottomRight[1]) { distances += float(len < radius && len > radius - thick);
// bottom right len = length(pixCoord + vec2(0.25, 0.75));
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, bottomRight); distances += float(len < radius && len > radius - thick);
done = true; len = length(pixCoord + vec2(0.75, 0.75));
} distances += float(len < radius && len > radius - thick);
if (distances == 0.0)
discard;
distances /= 4.0;
pixColor[3] *= distances;
} else if (dist > radius || dist < radius - thick)
discard;
done = true;
} }
// now check for other shit // now check for other shit
if (!done) { if (!done) {
// distance to all straight bb borders // distance to all straight bb borders
float distanceT = pixCoord[1]; float distanceT = originalPixCoord[1];
float distanceB = fullSize[1] - pixCoord[1]; float distanceB = fullSizeUntransformed[1] - originalPixCoord[1];
float distanceL = pixCoord[0]; float distanceL = originalPixCoord[0];
float distanceR = fullSize[0] - pixCoord[0]; float distanceR = fullSizeUntransformed[0] - originalPixCoord[0];
// get the smallest // get the smallest
float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR)); float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR));
if (smallest > thick) { if (smallest > thick)
discard; return; discard;
}
} }
if (pixColor[3] == 0.0) { if (pixColor[3] == 0.0)
discard; return; discard;
}
float pixColor3 = pixColor[3];
pixColor = getColorForCoord(v_texcoord);
pixColor[3] *= alpha * pixColor3;
gl_FragColor = pixColor; gl_FragColor = pixColor;
} }

View File

@@ -3,140 +3,38 @@
#include <string> #include <string>
inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string { inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string {
return R"#( return R"#(
if (pixCoord[0] < topLeft[0]) {
// we're close left
if (pixCoord[1] < topLeft[1]) {
// top
if (ignoreCorners == 1) { // branchless baby!
discard; highp vec2 pixCoord = vec2(gl_FragCoord);
return; pixCoord -= topLeft + fullSize * 0.5;
} pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
pixCoord -= fullSize * 0.5 - radius;
float topLeftDistance = distance(topLeft, pixCoord); if (pixCoord.x + pixCoord.y > radius) {
if (topLeftDistance > radius - 1.0) { float dist = length(pixCoord);
if (primitiveMultisample == 0 && topLeftDistance > radius) {
discard;
return;
} else if (primitiveMultisample == 1) {
float distances = 0.0;
if (distance(topLeft, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(topLeft, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(topLeft, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
if (distance(topLeft, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
if (distances == 0.0) { if (dist > radius)
discard; discard;
return;
}
distances = distances / 4.0; if (primitiveMultisample == 1 && dist > radius - 1.0) {
float distances = 0.0;
distances += float(length(pixCoord + vec2(0.25, 0.25)) < radius);
distances += float(length(pixCoord + vec2(0.75, 0.25)) < radius);
distances += float(length(pixCoord + vec2(0.25, 0.75)) < radius);
distances += float(length(pixCoord + vec2(0.75, 0.75)) < radius);
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances; if (distances == 0.0)
} discard;
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (ignoreCorners == 1) { distances /= 4.0;
discard;
return;
}
float topLeftDistance = distance(vec2(topLeft[0], bottomRight[1]), pixCoord); )#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
}
if (topLeftDistance > radius - 1.0) { }
if (primitiveMultisample == 0 && topLeftDistance > radius) { )#";
discard;
return;
} else if (primitiveMultisample == 1) {
float distances = 0.0;
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
if (distances == 0.0) {
discard;
return;
}
distances = distances / 4.0;
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
}
}
}
}
else if (pixCoord[0] > bottomRight[0]) {
// we're close right
if (pixCoord[1] < topLeft[1]) {
// top
if (ignoreCorners == 1) {
discard;
return;
}
float topLeftDistance = distance(vec2(bottomRight[0], topLeft[1]), pixCoord);
if (topLeftDistance > radius - 1.0) {
if (primitiveMultisample == 0 && topLeftDistance > radius) {
discard;
return;
} else if (primitiveMultisample == 1) {
float distances = 0.0;
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
if (distances == 0.0) {
discard;
return;
}
distances = distances / 4.0;
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
}
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (ignoreCorners == 1) {
discard;
return;
}
float topLeftDistance = distance(bottomRight, pixCoord);
if (topLeftDistance > radius - 1.0) {
if (primitiveMultisample == 0 && topLeftDistance > radius) {
discard;
return;
} else if (primitiveMultisample == 1) {
float distances = 0.0;
if (distance(bottomRight, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(bottomRight, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(bottomRight, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
if (distance(bottomRight, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
if (distances == 0.0) {
discard;
return;
}
distances = distances / 4.0;
)#" + colorVarName + R"#( = )#" + colorVarName + R"#( * distances;
}
}
}
}
)#";
}; };
inline const std::string QUADVERTSRC = R"#( inline const std::string QUADVERTSRC = R"#(
@@ -156,29 +54,22 @@ void main() {
inline const std::string QUADFRAGSRC = R"#( inline const std::string QUADFRAGSRC = R"#(
precision mediump float; precision mediump float;
varying vec4 v_color; varying vec4 v_color;
varying vec2 v_texcoord;
uniform vec2 topLeft; uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize; uniform vec2 fullSize;
uniform float radius; uniform float radius;
uniform int primitiveMultisample; uniform int primitiveMultisample;
uniform int ignoreCorners;
void main() { void main() {
if (radius == 0.0) {
gl_FragColor = v_color;
return;
}
vec4 pixColor = v_color; vec4 pixColor = v_color;
vec2 pixCoord = fullSize * v_texcoord;
if (radius > 0.0) {
)#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
}
gl_FragColor = pixColor; gl_FragColor = pixColor;
})#"; })#";
inline const std::string TEXVERTSRC = R"#( inline const std::string TEXVERTSRC = R"#(
@@ -188,8 +79,8 @@ attribute vec2 texcoord;
varying vec2 v_texcoord; varying vec2 v_texcoord;
void main() { void main() {
gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
v_texcoord = texcoord; v_texcoord = texcoord;
})#"; })#";
inline const std::string TEXFRAGSRCRGBA = R"#( inline const std::string TEXFRAGSRCRGBA = R"#(
@@ -199,7 +90,6 @@ uniform sampler2D tex;
uniform float alpha; uniform float alpha;
uniform vec2 topLeft; uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize; uniform vec2 fullSize;
uniform float radius; uniform float radius;
@@ -209,29 +99,24 @@ uniform int applyTint;
uniform vec3 tint; uniform vec3 tint;
uniform int primitiveMultisample; uniform int primitiveMultisample;
uniform int ignoreCorners;
void main() { void main() {
vec4 pixColor = texture2D(tex, v_texcoord); vec4 pixColor = texture2D(tex, v_texcoord);
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { if (discardOpaque == 1 && pixColor[3] * alpha == 1.0)
discard; discard;
return;
}
if (applyTint == 1) {
pixColor[0] = pixColor[0] * tint[0];
pixColor[1] = pixColor[1] * tint[1];
pixColor[2] = pixColor[2] * tint[2];
}
vec2 pixCoord = fullSize * v_texcoord; if (applyTint == 1) {
pixColor[0] = pixColor[0] * tint[0];
pixColor[1] = pixColor[1] * tint[1];
pixColor[2] = pixColor[2] * tint[2];
}
)#" + ROUNDED_SHADER_FUNC("pixColor") + )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
R"#(
gl_FragColor = pixColor * alpha; gl_FragColor = pixColor * alpha;
})#"; })#";
inline const std::string TEXFRAGSRCRGBX = R"#( inline const std::string TEXFRAGSRCRGBX = R"#(
@@ -241,7 +126,6 @@ uniform sampler2D tex;
uniform float alpha; uniform float alpha;
uniform vec2 topLeft; uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize; uniform vec2 fullSize;
uniform float radius; uniform float radius;
@@ -251,29 +135,23 @@ uniform int applyTint;
uniform vec3 tint; uniform vec3 tint;
uniform int primitiveMultisample; uniform int primitiveMultisample;
uniform int ignoreCorners;
void main() { void main() {
if (discardOpaque == 1 && alpha == 1.0) { if (discardOpaque == 1 && alpha == 1.0)
discard; discard;
return;
}
vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0); vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0);
if (applyTint == 1) { if (applyTint == 1) {
pixColor[0] = pixColor[0] * tint[0]; pixColor[0] = pixColor[0] * tint[0];
pixColor[1] = pixColor[1] * tint[1]; pixColor[1] = pixColor[1] * tint[1];
pixColor[2] = pixColor[2] * tint[2]; pixColor[2] = pixColor[2] * tint[2];
} }
vec2 pixCoord = fullSize * v_texcoord; )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
)#" + ROUNDED_SHADER_FUNC("pixColor") + gl_FragColor = pixColor * alpha;
R"#(
gl_FragColor = pixColor * alpha;
})#"; })#";
inline const std::string FRAGBLUR1 = R"#( inline const std::string FRAGBLUR1 = R"#(
@@ -286,13 +164,14 @@ uniform float radius;
uniform vec2 halfpixel; uniform vec2 halfpixel;
void main() { void main() {
vec2 uv = v_texcoord * 2.0; vec2 uv = v_texcoord * 2.0;
vec4 sum = texture2D(tex, uv) * 4.0; vec4 sum = texture2D(tex, uv) * 4.0;
sum += texture2D(tex, uv - halfpixel.xy * radius); sum += texture2D(tex, uv - halfpixel.xy * radius);
sum += texture2D(tex, uv + halfpixel.xy * radius); sum += texture2D(tex, uv + halfpixel.xy * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius); sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius); sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
gl_FragColor = sum / 8.0; gl_FragColor = sum / 8.0;
} }
)#"; )#";
@@ -307,7 +186,7 @@ uniform float radius;
uniform vec2 halfpixel; uniform vec2 halfpixel;
void main() { void main() {
vec2 uv = v_texcoord / 2.0; vec2 uv = v_texcoord / 2.0;
vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius); vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius);
@@ -332,7 +211,6 @@ uniform samplerExternalOES texture0;
uniform float alpha; uniform float alpha;
uniform vec2 topLeft; uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize; uniform vec2 fullSize;
uniform float radius; uniform float radius;
@@ -342,27 +220,22 @@ uniform int applyTint;
uniform vec3 tint; uniform vec3 tint;
uniform int primitiveMultisample; uniform int primitiveMultisample;
uniform int ignoreCorners;
void main() { void main() {
vec4 pixColor = texture2D(texture0, v_texcoord); vec4 pixColor = texture2D(texture0, v_texcoord);
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) { if (discardOpaque == 1 && pixColor[3] * alpha == 1.0)
discard; discard;
return;
}
if (applyTint == 1) { if (applyTint == 1) {
pixColor[0] = pixColor[0] * tint[0]; pixColor[0] = pixColor[0] * tint[0];
pixColor[1] = pixColor[1] * tint[1]; pixColor[1] = pixColor[1] * tint[1];
pixColor[2] = pixColor[2] * tint[2]; pixColor[2] = pixColor[2] * tint[2];
} }
vec2 pixCoord = fullSize * v_texcoord; )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
)#" + ROUNDED_SHADER_FUNC("pixColor") + gl_FragColor = pixColor * alpha;
R"#( }
)#";
gl_FragColor = pixColor * alpha;
})#";