Compare commits

..

689 Commits

Author SHA1 Message Date
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
vaxerski
ff5843bd85 anchor to proper quad in floating resize 2022-10-03 22:41:12 +01:00
vaxerski
3bb5971c2e [gha] bump flake inputs 2022-10-03 21:17:33 +00:00
vaxerski
a1d9404f9f update wlroots dep 2022-10-03 22:16:02 +01:00
vaxerski
ab82c4806d allow one less arg in bind 2022-10-03 21:01:08 +01:00
vaxerski
49ab3890aa remove polling from socket2, fully event based 2022-10-03 20:47:15 +01:00
vaxerski
85eea70be4 fix commas in free binds 2022-10-03 16:38:05 +01:00
vaxerski
174b593438 optimize removing trailing spaces 2022-10-03 14:36:56 +01:00
vaxerski
0a08830375 Unify arg lists, allow for trailing spaces in args 2022-10-03 14:29:45 +01:00
vaxerski
a97621b1cb Added window swallowing 2022-10-01 19:19:15 +01:00
vaxerski
355366714e minor OR XWayland fixes 2022-10-01 18:25:02 +01:00
vaxerski
590fbf808b send a focusedmon event on focus change mon 2022-10-01 10:38:53 +01:00
vaxerski
bbeed21e62 fix crash 2022-10-01 08:54:43 +01: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
vaxerski
e6c9e3f81d add case for empty strings in isNumber 2022-09-30 21:54:13 +01:00
vaxerski
7579e03b64 include shaders only in opengl.cpp 2022-09-30 18:38:10 +01:00
vaxerski
1ef23a304a remove redundant attrib setting 2022-09-30 17:04:33 +01:00
vaxerski
3c27d1ab13 optimize vector config value setting 2022-09-30 17:03:14 +01:00
vaxerski
59a3c43913 guard event in maximize request 2022-09-30 10:37:09 +01: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
vaxerski
2d73da1a79 enter outputs for non-interactive ls-es too 2022-09-29 22:16:43 +01:00
Vaxry
45fe185cb9 Merge pull request #736 from Dickby/fix_bordersize_again
Scale the border size, revert the window scaling according to border
2022-09-29 22:01:06 +01: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
vaxerski
da40bf823f apply new node data to all group windows on close 2022-09-29 19:46:33 +01:00
vaxerski
caeb0636fa fix crash on dwindle splitratio alter on single group 2022-09-29 19:41:49 +01:00
Felix Dick
1424539e4d Merge branch 'main' into rework_rounding_shader 2022-09-29 20:41:39 +02:00
vaxerski
bdd9680adf fix ipc event missing on silent movetoworkspace 2022-09-29 19:33:43 +01:00
vaxerski
ff4c22ca90 add fullscreen info to clients request 2022-09-29 19:30:49 +01:00
vaxerski
9f9129e536 focusable checks in nextWindow calls 2022-09-29 16:53:31 +01:00
Felix Dick
ab42e4bccf Merge branch 'main' into fix_bordersize_again 2022-09-29 14:29:03 +02:00
Felix Dick
425b07d1e5 Merge branch 'main' into rework_rounding_shader 2022-09-29 14:24:59 +02:00
vaxerski
2636abca2d use the event data for determining maximize status in requests 2022-09-29 10:24:54 +01:00
vaxerski
ead0e74471 handle maximize toplevel request 2022-09-29 10:20:17 +01:00
Vaxry
dcf5e34bfa Merge pull request #735 from Dickby/fix_splash_position
Splash position fix
2022-09-29 10:07:27 +01: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
10c4f4ba35 Shift splash up if monitor has wider ratio than bgTexture. 2022-09-29 05:29:03 +02:00
Felix Dick
a1319e5110 Merge branch 'main' into fix_bordersize_again 2022-09-29 01:42:28 +02:00
Felix Dick
5233746ac5 Change scaledBorderSize to int. 2022-09-29 01:40:19 +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
Vaxry
31cb4c49d9 Merge pull request #743 from Dickby/use_double_literals
Use double literals, don't cast integer or float literals to double.
2022-09-28 19:28:13 +01:00
Felix Dick
11ee78f88b Use double literals, don't cast a integer literal to double. 2022-09-28 20:08:41 +02:00
Felix Dick
7edbaea23d Make the rounding texture shaders smaller and more efficient. 2022-09-28 18:40:04 +02:00
vaxerski
ec5ffe8839 rewrite isNumber 2022-09-28 15:32:53 +01:00
vaxerski
e3b1d3c3c5 allow for pure workspace names in dispatchers 2022-09-28 15:26:41 +01:00
vaxerski
458ba3237b use goalv in movetoworkspace 2022-09-28 15:12:15 +01:00
Felix Dick
5ff44467d7 Avoid 38 files to compile every time a shader is modified. 2022-09-28 14:48:05 +02:00
Vaxry
7a775c0584 Merge pull request #737 from Dickby/use_max_instead_of_clamp_in_some_places
Replace clamp with max if there is no upper bound.
2022-09-26 20:49:56 +01:00
Felix Dick
87afc8c250 Replace clamp with max if there is no upper bound. 2022-09-26 21:10:24 +02:00
Felix Dick
cd2b2c4fba Scale the border size, revert the window scaling according to border 2022-09-26 17:38:08 +02:00
Felix Dick
c48336aac3 Scale the cairo matrix to fit the monitor dimensions. 2022-09-26 06:35:00 +02:00
Vaxry
f70b57f360 Merge pull request #732 from Dickby/main
Remove trailing whitespace.
2022-09-25 19:32:24 +01:00
Felix Dick
bf3f519eb7 Remove trailing whitespace. 2022-09-25 20:07:48 +02:00
Vaxry
190229942f Merge pull request #727 from Dickby/main
Scale border size in window size pos calculation
2022-09-25 17:21:31 +01:00
Dickby
e476382d08 scale border size in dwindle layout window sizes. 2022-09-25 18:12:42 +02:00
Dickby
c885afcbc6 Scale border size in calculations of windows 2022-09-25 12:42:39 +02:00
vaxerski
fad5fc587d guard kb settings in xkb translation state 2022-09-24 21:07:18 +01:00
vaxerski
73dbacd16d overwrite wsbind rules on existing 2022-09-24 13:42:18 +01:00
vaxerski
65fb0cf0f6 fix custom rules on null modelist 2022-09-24 13:10:11 +01:00
vaxerski
5101ddeff1 fix oopsies in rule code 2022-09-24 11:30:41 +01:00
Vaxry
959557ecc3 Merge pull request #716 from Dickby/main
Fixing my last change
2022-09-23 18:18:55 +01:00
Dickby
bccc81d306 Fixing my last change
It wasn't a problem with the bug i tried to fix.
But there  would be a problem if some function would dereference pPreviousGroupMember from the node that was PHEAD->pNextGroupMember.
Please don't be mean!
2022-09-23 19:13:05 +02:00
Vaxry
718de0d9fa Merge pull request #715 from Dickby/main
fix crash
2022-09-23 17:05:04 +01:00
vaxerski
fd6116c0cd style 2022-09-23 17:01:27 +01:00
Dickby
00b16888bf style fix 2022-09-23 17:59:33 +02:00
Vaxry
abee2da5bd Merge pull request #706 from DashieTM/main
Add "highest" mode to Monitor for autoconfiguration.
2022-09-23 16:50:24 +01:00
vaxerski
695411f1bd don't decorate on only no gaps 2022-09-23 16:47:58 +01:00
Dickby
f9d8b3096a fix crash
Fixes #711
2022-09-23 17:01:46 +02:00
vaxerski
e5d143b238 support more wlr_cursor events 2022-09-22 21:14:02 +01:00
vaxerski
37f2e1ddbe don't recalc pseudo on fullscreen 2022-09-22 20:57:09 +01:00
vaxerski
ef3eb37c7f support max in size rules 2022-09-22 18:13:23 +01:00
Mihai Fufezan
db551b8970 Nix & meson: bump to 0.14.0 2022-09-22 19:59:38 +03:00
vaxerski
c08218301b disallow pinning fullscreen 2022-09-22 16:48:40 +01:00
vaxerski
75aaf11a9c default pass_mouse_when_bound to 0 2022-09-22 16:33:45 +01:00
Fabio Lenherr
c4e782ca5d remove more silly mistakes 2022-09-22 00:50:23 +02:00
Fabio Lenherr
da2c2ddc21 remove empty line 2022-09-22 00:47:09 +02:00
Fabio Lenherr
5272588270 fix silly mistakes 2022-09-22 00:45:56 +02:00
Fabio Lenherr
215125bd66 add refreshrate or resolution preference 2022-09-22 00:22:39 +02:00
Fabio Lenherr
30d16373d0 fix Hz Log 2022-09-21 22:40:01 +02:00
Fabio Lenherr
c1feb683ce added high to monitor resolution 2022-09-21 22:29:52 +02:00
vaxerski
d3ffccd45f accept any case in binds 2022-09-21 17:41:26 +01:00
Mihai Fufezan
d49af1cc18 flake: add libdrm overlay until it gets updated 2022-09-21 18:10:35 +03:00
vaxerski
8b46d0b5a9 simplify some local vars 2022-09-21 15:11:09 +01:00
vaxerski
336883dda3 [gha] bump flake inputs 2022-09-21 14:09:05 +00:00
vaxerski
65ec8c7694 update wlroots dep 2022-09-21 15:07:57 +01:00
vaxerski
79c645f8cd handle touch devices internally as objects 2022-09-21 14:39:34 +01:00
vaxerski
d44cc9f112 [gha] bump flake inputs 2022-09-21 13:23:15 +00:00
vaxerski
1963da2d47 update wlroots dep 2022-09-21 14:22:05 +01:00
vaxerski
2b99dbb446 better cycling in fullscreen with pinned 2022-09-21 14:16:13 +01:00
vaxerski
d24f31de51 disallow fullscreen pinned 2022-09-21 14:09:26 +01:00
Fabio Lenherr / DashieTM
d51c7ca135 change Preferred mode to use highest refreshrate 2022-09-20 23:41:03 +02:00
vaxerski
8b11a2e1b1 minor mouse bind handling fixes 2022-09-20 22:23:02 +01:00
vaxerski
b4bcba935d disallow move/resize dispatchers on fullscreen windows 2022-09-20 19:58:08 +01:00
vaxerski
7f3750bd75 disable enabling groups on fullscreen windows 2022-09-20 18:08:10 +01:00
vaxerski
7a9423c782 better dwindle swapping with groups 2022-09-20 18:04:39 +01:00
vaxerski
6f98b3cbd8 fix pinned fade on fs 2022-09-20 15:33:53 +01:00
vaxerski
2dd1661aec fix groups with fullscreen 2022-09-20 12:17:34 +01:00
vaxerski
cde624ec6a fix moving between fullscreen workspaces 2022-09-20 10:16:58 +01:00
vaxerski
b82621c4ec fix mouse binds being stuck 2022-09-20 10:02:20 +01:00
vaxerski
5b6c8d5b0f fix misc fullscreen issues 2022-09-20 09:55:25 +01:00
vaxerski
4dca2b945b fix LS fading out on ws change 2022-09-20 09:46:55 +01:00
Vaxry
a8943246a7 Merge pull request #684 from tomahk/main
fix some bugs with attaching/disabling monitors
2022-09-19 21:08:48 +01:00
vaxerski
e42de0b778 export HYPRLAND_CMD for scripts 2022-09-19 21:06:44 +01:00
tomahk
5146165599 this is c++, use nullptr 2022-09-19 21:45:00 +02:00
tomahk
73e19aee6f prevent assert killing Hyprland after reenabling monitor 2022-09-19 20:44:33 +02:00
tomahk
3780361b95 fix hyprland freeze when undocking from docking station 2022-09-19 20:42:59 +02:00
vaxerski
ec6144e5da fix fadeout on unmap fullscreen 2022-09-19 19:09:21 +01:00
vaxerski
b6eaeffcf6 introduce new mouse binds in default and example cfgs 2022-09-19 19:06:22 +01:00
vaxerski
c24b45671a mouse binds overhaul 2022-09-19 19:04:48 +01:00
vaxerski
85c7aaf155 fade control for fullscreen action on windows 2022-09-19 17:26:11 +01:00
vaxerski
696253b348 fix special workspace dispatcher logic 2022-09-19 16:01:42 +01:00
vaxerski
abb6db9c37 don't apply alpha to fadingOut on setWindowFullscreen 2022-09-19 11:44:11 +01:00
vaxerski
18b483b8e1 fix ws switching with LS opacity 2022-09-19 10:40:42 +01:00
vaxerski
7c809a3059 fullscreen animation en-nice-ment 2022-09-19 10:23:13 +01:00
vaxerski
4070e1a148 fix wonky focus on movetoworkspace 2022-09-18 17:26:12 +01:00
vaxerski
dd61f88ed1 guard invalid FB allocs 2022-09-18 12:40:49 +01:00
vaxerski
29626989e7 fix focus follows mouse 0 event sending on wrong window 2022-09-18 12:35:05 +01:00
vaxerski
cf32d28082 fix groupbar being wonk on scaled 2022-09-18 12:13:16 +01:00
vaxerski
5131a4acaf fix special fullscreen 2022-09-17 15:07:03 +01:00
vaxerski
a72a39ebd5 minor swipe fixes 2022-09-17 15:05:12 +01:00
vaxerski
151e013241 fix refocus on same workspace 2022-09-17 12:10:06 +01:00
vaxerski
fa2d81b649 fix animation issues with workspace silent 2022-09-16 21:17:03 +01:00
vaxerski
037d4ed422 handle multi-ws swaps in layouts 2022-09-14 17:30:16 +02:00
vaxerski
9f82278d65 simplify dwindle swap 2022-09-14 17:24:45 +02:00
vaxerski
8e0f7b9b11 Various subsurface handling fixes 2022-09-14 16:34:41 +02:00
vaxerski
a96acc8fa4 only check for visible on xdg 2022-09-13 22:23:48 +02:00
vaxerski
5a146e9d90 guard surface in addsurfaceglobaloffset 2022-09-13 21:49:55 +02:00
vaxerski
da10022d84 fix an unholy memory safety issue 2022-09-13 20:27:07 +02:00
vaxerski
e518adf1ac don't iterate over subsurfaces in unmap 2022-09-13 15:44:50 +02:00
vaxerski
d8dbe26f31 tick config after reload request 2022-09-13 15:36:49 +02:00
vaxerski
e9f226797e Added monitor mirroring 2022-09-13 15:25:42 +02:00
vaxerski
7d4f0a3199 verify visibility of new geom in floating creation 2022-09-13 12:29:56 +02:00
vaxerski
0062281092 added wsbind 2022-09-12 21:05:52 +02:00
vaxerski
81f267dff9 add default speed to hyprctl devices mice 2022-09-12 17:09:04 +02:00
vaxerski
a09c614c2d more forceRendering checks in shouldRenderWindow 2022-09-12 15:33:25 +02:00
Vaxry
b49d7007b5 Merge pull request #659 from hyprwm/hyprctl-nopoll
hyprctl-nopoll
2022-09-11 20:48:22 +02:00
vaxerski
864e227f5d fix decos on pinned 2022-09-11 20:27:59 +02:00
vaxerski
82aa78916d hyprctl-nopoll 2022-09-10 21:21:28 +02:00
vaxerski
f024d7114f allow current in monitorfromstring 2022-09-10 19:57:57 +02:00
vaxerski
8808d40008 added misc:disable_autoreload 2022-09-10 17:28:41 +02:00
vaxerski
d94fe3d063 added window pinning 2022-09-10 13:11:02 +02:00
vaxerski
f663fa209c minor code styling fixes 2022-09-09 19:08:11 +02:00
Mihai Fufezan
9370c7aa8a Nix modules: add recommendedEnvironment option 2022-09-09 17:01:24 +03:00
vaxerski
928158bbfb prevent missed surface size updates on fullscreen window close 2022-09-08 23:02:29 +02:00
vaxerski
bacfae3084 guard drag in destroyDrag 2022-09-08 21:25:16 +02:00
vaxerski
0d95a0174c more guarding in cleanup pid gathering 2022-09-08 20:55:25 +02:00
vaxerski
0eb5ecafb9 consistent output of window addresses 2022-09-08 18:47:39 +02:00
vaxerski
49a55f136e fix addreserved lag 2022-09-08 14:11:32 +02:00
vaxerski
64be57b780 fix group decos on added windows 2022-09-07 20:36:39 +02:00
Vaxry
6e195a6b8c Merge pull request #636 from viperML/fix-man
docs: fix github workflow
2022-09-07 13:05:16 +02:00
Fernando Ayats
8d3f6c5d84 docs: fix github workflow 2022-09-07 12:44:20 +02:00
vaxerski
5c470d2e54 damage drag on destroy 2022-09-07 12:18:52 +02:00
Mihai Fufezan
26910a8b63 Nix HM module: fix build error
Apparently HM doesn't like having `lib.mkDefault` near strings.

Fixes #635
2022-09-07 13:11:03 +03:00
vaxerski
44a2d755c6 Added Xwayland and floating props to windowrulev2 2022-09-07 11:25:44 +02:00
Mars
cf5426f2d8 Fix typo in module.nix 2022-09-07 11:48:08 +03:00
Mihai Fufezan
1d631c8a23 Nix modules: add common environment variables 2022-09-07 01:24:09 +03:00
vaxerski
789eedd115 fix a minor bug with no gaps when only and groups 2022-09-06 19:59:59 +02:00
vaxerski
4a8274e5f0 fix dwindle no gaps when only when dissolving a group 2022-09-06 18:12:41 +02:00
vaxerski
4b7d28d2cb fix last partial commit 2022-09-06 18:12:25 +02:00
vaxerski
5fdd1dd60f simplify config monitor reloads and rearrange layers 2022-09-06 17:26:18 +02:00
vaxerski
e71a4d75de Added windowrulev2 2022-09-06 11:57:11 +02:00
vaxerski
f002bd1603 wrap lastwindow in quotes in hyprctl json 2022-09-05 23:07:56 +02:00
vaxerski
16f1d1b99b guard unsafe state in unmap ls 2022-09-05 22:35:41 +02:00
vaxerski
c1bc8d46e9 use lastMonitor in mapWindow 2022-09-05 22:04:49 +02:00
vaxerski
94ca386a8c set last monitor and dont refocus in some cases (changeworkspace) 2022-09-05 21:36:22 +02:00
vaxerski
2ba7cb2414 escape json strings in workspaces lastwindow title 2022-09-05 21:32:37 +02:00
vaxerski
5b5f36f494 fix transformed blur on new optimizations 2022-09-05 21:26:21 +02:00
vaxerski
a74b8033ca added a submap IPC event 2022-09-05 13:50:52 +02:00
vaxerski
41883e0522 fix wonky behavior with silent workspace rule 2022-09-05 11:44:43 +02:00
vaxerski
3ea89e6171 fix splash positioning 2022-09-05 11:31:54 +02:00
vaxerski
d6c06318af don't accumulate from virtual 2022-09-05 11:19:40 +02:00
vaxerski
cb839c9dcc guard pFoundWindow in CInputManager under fullscreen 2022-09-05 00:59:13 +02:00
vaxerski
3dd514a452 fix a damage issue with transformed blur 2022-09-04 23:08:04 +02:00
vaxerski
6afab12b91 fix blur on transformed displays 2022-09-04 19:27:38 +02:00
vaxerski
7a3b57c99c send accumulated modifiers to surfaces 2022-09-04 18:46:28 +02:00
vaxerski
ba0c5fe0bb fix mouse focus not returning from a LS on follow mouse 0 2022-09-04 18:42:11 +02:00
vaxerski
f6ecef0959 add lastwindow info to hyprctl workspaces 2022-09-04 18:32:03 +02:00
vaxerski
ff26531e11 use activateSurface in unconstrainMouse 2022-09-04 11:29:49 +02:00
vaxerski
fbd2b4799d Fix some more crimes against humanity 2022-09-03 22:49:52 +02:00
Mihai Fufezan
1664f81cae Nix: revert HM module import fix
fixes #619
2022-09-03 23:22:39 +03:00
vaxerski
c425e620af fix some minor crimes against humanity 2022-09-03 19:35:17 +02:00
vaxerski
f4add0ac6d refocus on reserved area 2022-09-03 15:35:53 +02:00
vaxerski
3c3f80c2fe simplify code and update monitor on warp 2022-09-03 11:55:19 +02:00
Mihai Fufezan
eee0cad4d0 Nix modules: fix imports 2022-09-03 02:20:20 +03:00
Mihai Fufezan
0ea96e87c0 flake: remove overlay warning 2022-09-03 01:55:28 +03:00
vaxerski
5d09bb647b fix up styling 2022-09-02 23:56:22 +02:00
vaxerski
f5697095bc unify monitor args 2022-09-02 11:53:12 +02:00
vaxerski
56203b1757 fix no_gaps_when_only with a group 2022-09-01 19:46:38 +02:00
Fernando Ayats
c0a7dffcdc nix: move wlroots and add nvidia patches (#608) 2022-09-01 20:35:50 +03:00
vaxerski
8581e71789 optimize calls in toggleSpecialWorkspace 2022-09-01 11:47:48 +02:00
vaxerski
bb90ff0461 sanity check on last window 2022-09-01 11:46:41 +02:00
vaxerski
1d4d2f4793 [gha] bump flake inputs 2022-09-01 09:25:26 +00:00
vaxerski
7f62cbc48a Update wlroots dep 2022-09-01 11:24:15 +02:00
vaxerski
f2d84a7e3a guard parent in X11TransientFor 2022-09-01 10:16:23 +02:00
vaxerski
095185cfe7 guard parent in X11TransientFor 2022-09-01 10:15:55 +02:00
vaxerski
f77fac9df9 warp only on another monitor in changeworkspace 2022-08-31 21:39:27 +02:00
vaxerski
dacaf72e02 remember last window on workspace 2022-08-31 17:02:49 +02:00
Mihai Fufezan
0ad261aa9c flake: formatting 2022-08-31 12:26:12 +03:00
Mihai Fufezan
7610c20761 Nix & meson: 0.11.1 -> 0.12.1
flake: add commit to wlroots version
2022-08-31 12:22:32 +03:00
vaxerski
4103bca056 default rounding to 0 2022-08-31 11:17:04 +02:00
vaxerski
21a1b62b6a remove tiling node when invalid 2022-08-31 11:14:33 +02:00
vaxerski
7f483dfdb0 guard psurface in activateSurface 2022-08-31 11:12:46 +02:00
vaxerski
1cf46fd6a2 added closewindow dispatcher 2022-08-30 21:35:27 +02:00
vaxerski
eb658dcb61 finally fixed transformed snapshots 2022-08-30 19:40:19 +02:00
vaxerski
195ec2b092 fix LS popup damage 2022-08-30 19:21:45 +02:00
vaxerski
dd6aba07e9 revert x11 size hints 2022-08-30 16:12:11 +02:00
vaxerski
d35d949bc5 use sizehints if existent for X11 default floating 2022-08-30 13:07:54 +02:00
vaxerski
48eb2e0d6f Added window dimming 2022-08-30 12:46:17 +02:00
vaxerski
179562b646 fix dwindle groupbars 2022-08-29 19:52:35 +02:00
vaxerski
20c050e890 set last monitor on move focus dispatcher 2022-08-29 18:50:10 +02:00
Mihai Fufezan
bdd20c401d Add HiDPI xwayland + wlroots patches (#591) 2022-08-29 16:51:39 +03:00
vaxerski
6865660e51 disable fullscreen and floating dispatchers on special 2022-08-29 14:55:11 +02:00
vaxerski
6c8ce734fb fix segfault in inactive sessions 2022-08-29 11:17:42 +02:00
vaxerski
09495375b5 ratelimit setting cursor 2022-08-28 22:45:05 +02:00
vaxerski
3c20ecb04d ignore oversized popups' dims in global coords 2022-08-28 21:20:18 +02:00
vaxerski
5da114477f move X11 transients to top on parent top 2022-08-28 19:47:06 +02:00
vaxerski
c757fa54e1 Allow passing the mouse as well in pass 2022-08-28 17:01:48 +02:00
vaxerski
16f8d46391 Force wlroots to not send leave events in pass to XWayland
Massive hack, kill me
2022-08-28 16:43:15 +02:00
vaxerski
5726f394b1 fix subsurface UV handling on oversized windows 2022-08-28 14:43:25 +02:00
vaxerski
f5f99c6700 reset uv on invalid buffer source box 2022-08-28 14:32:06 +02:00
vaxerski
cfa6c01df0 remove double drm and dmabuf creation 2022-08-28 12:32:26 +02:00
vaxerski
d413388761 Multiple improvements to the shutdown procedure 2022-08-28 11:19:08 +02:00
vaxerski
4203a61b69 minor fixes to the viewporter behavior 2022-08-28 10:41:47 +02:00
vaxerski
80b3a436d2 better find device cats 2022-08-28 10:25:48 +02:00
vaxerski
5d9d55a245 fix device closing 2022-08-28 10:20:26 +02:00
Vaxry
52c0ba544c Viewporter implementaion (#585)
Implementation of the `wp_viewporter` core protocol and some bugfixes
2022-08-28 10:14:43 +02:00
Vaxry
8b5c64c8fd Merge pull request #589 from alec-lefors/drm-leasing
fix more indents
2022-08-28 00:07:01 +02:00
Alec LeFors
2ea5f50f40 fix more indents, im sorry vaxry 2022-08-27 17:57:02 -04:00
Vaxry
1d97ad9856 Merge pull request #588 from alec-lefors/drm-leasing
implemented DRM leasing
2022-08-27 23:47:41 +02:00
Alec LeFors
1d43bb70d4 fix indents, change crit log to info 2022-08-27 17:24:36 -04:00
vaxerski
573cb0d4e0 fix parser in nested categories 2022-08-27 23:12:01 +02:00
Alec LeFors
59d7cfcd02 implemented DRM leasing for VR headsets 2022-08-27 17:10:13 -04:00
vaxerski
ed2cacc5d5 fix styling in const ptrs 2022-08-27 21:37:35 +02:00
Nicholas Cioli
df4c1c02a6 fix xwayland config option for nix (#587)
When building Hyprland in nix using the following home-manager recipe:

```nix
wayland.windowManager.hyprland = {
    enable = true;
    xwayland = false;
  };
```

The default nix configuration still makes reference to a compile argument `NO_XWAYLAND`, but the `meson_options.txt` only makes reference to `xwayland`. This causes the build to fail with:

```
meson.build:1:0: ERROR: Unknown options: "NO_XWAYLAND"
```

This change fixes that issue. This still doesn't allow you to build Hyprland without having XWayland installed (#178), but it should at least allow for valid nix configurations for when that issue gets resolved.
2022-08-27 21:45:48 +03:00
vaxerski
8122505825 pass press and release events separately 2022-08-27 19:29:28 +02:00
vaxerski
0964448f93 fix fullscreen in moving ws 2022-08-27 19:11:21 +02:00
vaxerski
5d63152219 added a forceinput rule 2022-08-27 13:01:55 +02:00
vaxerski
aaa834d0c3 fix logic in candidates on unmap 2022-08-27 12:02:25 +02:00
vaxerski
28966d85ae guard nullptr in unmap 2022-08-27 12:01:04 +02:00
vaxerski
a648b452dd fix internal keybinds 2022-08-26 19:19:34 +02:00
vaxerski
d53b0a6491 optimize options in dwindle 2022-08-26 19:07:33 +02:00
Mihai Fufezan
80d522cb26 nix & meson: update version to 0.11.1 2022-08-26 19:48:22 +03:00
vaxerski
dbd774fedb simplify a bit of code 2022-08-26 18:02:10 +02:00
Mihai Fufezan
bf00bf7963 Nix: add nixConfig 2022-08-26 18:58:42 +03:00
vaxerski
949655005a added an event for moving workspace 2022-08-26 16:05:02 +02:00
Vaxry
56caba5f01 updated readme previews 2022-08-26 11:41:07 +02:00
vaxerski
b09f157b93 fix fullscreen on workspace rule silent 2022-08-26 11:33:36 +02:00
vaxerski
10f529ada7 added a specialWorkspace anim leaf 2022-08-26 11:26:23 +02:00
vaxerski
f7c741317f fix shadows on silent rule 2022-08-26 01:08:11 +02:00
vaxerski
b16a57ceeb fix window rules 2022-08-26 00:38:20 +02:00
vaxerski
0eb86f4b0d fix silent workspaces with back and forth 2022-08-26 00:19:57 +02:00
vaxerski
7b01c3d028 allow specifying window for toggle floating 2022-08-25 22:34:53 +02:00
vaxerski
89018bfa95 remove leftover code that didnt work 2022-08-25 21:38:01 +02:00
vaxerski
0d1a9e4ba9 modify exit behaviour a bit 2022-08-25 21:35:47 +02:00
vaxerski
e327b0a835 added a swapactiveworkspaces dispatcher 2022-08-25 21:25:28 +02:00
vaxerski
de477a6ff5 don't focus silent windows 2022-08-25 16:47:33 +02:00
Vaxry
e92469121d Merge pull request #573 from NotAShelf/main
Add cleaninstall task
2022-08-24 22:05:27 +02:00
NotAShelf
a9761cb1c8 Merge branch 'hyprwm:main' into main 2022-08-24 23:05:22 +03:00
vaxerski
6c2175ed52 fixes to swapnext logic on dwindle 2022-08-24 22:01:25 +02:00
vaxerski
00ef40dda1 added swapnext and swapprev for master 2022-08-24 21:50:48 +02:00
vaxerski
9c3aeda9f9 added swapnext 2022-08-24 21:40:36 +02:00
NotAShelf
a4f7bd4bc2 fix typo
what is this, clash of clans?
2022-08-24 18:53:30 +03:00
NotAShelf
3fd903ee74 remove unintended whitespace 2022-08-24 18:51:57 +03:00
NotAShelf
83ef951c21 add clean install for those who build from source 2022-08-24 18:47:35 +03:00
NotAShelf
8bbb790d87 [gha] build man pages 2022-08-24 15:46:38 +00:00
vaxerski
ffaf14c19e minor damage fixes 2022-08-24 13:44:48 +02:00
vaxerski
9366c187dc don't find a new candidate to refocus on unfocused unmap 2022-08-24 11:14:11 +02:00
vaxerski
29696d046e remove general:sensitivity from the default config 2022-08-24 11:12:42 +02:00
vaxerski
09f3999b1e Unfocus first on non-internal ws changes 2022-08-23 23:34:36 +02:00
vaxerski
fba7ed97fb don't refocus if candidate is last window 2022-08-23 23:15:04 +02:00
vaxerski
fd70a9184b fix logic in fullscreen close candidates 2022-08-23 23:09:28 +02:00
vaxerski
0a9ac47030 remove unintuitive candidate behavior 2022-08-23 18:25:33 +02:00
vaxerski
e2450247c0 minor fixes to candidate finding 2022-08-23 18:18:18 +02:00
vaxerski
973540bbc5 minor fix on unfocus on fullscreen workspace 2022-08-23 18:01:22 +02:00
vaxerski
f9b2aa5468 don't round popups 2022-08-23 16:54:32 +02:00
vaxerski
451659ec34 fix oversized popup misalignment 2022-08-23 16:52:36 +02:00
vaxerski
a9e34cba93 move monitor damage to separate funcs 2022-08-23 16:07:47 +02:00
vaxerski
48c9e9d83d damage on force warp resize 2022-08-23 15:08:15 +02:00
vaxerski
23c5760538 IME Popup damage fixes 2022-08-23 11:16:35 +02:00
vaxerski
9bfa3ebc50 fix up keyword to accept spaced args 2022-08-22 23:25:11 +02:00
Mihai Fufezan
8feb6f7da1 Nix: add shortRev to version 2022-08-23 00:17:00 +03:00
vaxerski
fb0e81c18e fix up hyprctl dispatch 2022-08-22 19:16:35 +02:00
vaxerski
359df96d53 fix wlr logging 2022-08-22 18:58:29 +02:00
vaxerski
63493b5736 use a custom logging func for wlr 2022-08-22 18:50:38 +02:00
vaxerski
6565c31dbf fix IME grab on multiple open native inputs 2022-08-22 18:40:38 +02:00
vaxerski
575bfa40e5 added misc:float_switch_override_focus 2022-08-22 18:22:26 +02:00
vaxerski
429b2bffed fix minor refocus issue 2022-08-22 18:16:32 +02:00
vaxerski
c83948ea9a added HYPRLAND_LOG_WLR envvar 2022-08-22 15:50:08 +02:00
vaxerski
8a6e29974b [gha] build man pages 2022-08-22 13:16:57 +00:00
Vaxry
4c6d9b7d5a Merge pull request #555 from viperML/update-man
docs: build man pages to repo
2022-08-22 15:16:32 +02:00
Vaxry
9f5e099cd1 Merge pull request #562 from sp1ritCS/s/ospatches
openSUSE patches
2022-08-22 14:47:17 +02:00
vaxerski
8b39a1cf9b always use /usr/share/ for wayland-sessions 2022-08-22 14:46:53 +02:00
Florian sp1rit​
e9551731f0 improve compatability with older meson versions
- changed <compiler>.get_version() to <compiler>.version()

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

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

View File

@@ -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

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

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

View File

@@ -5,6 +5,11 @@ jobs:
nix: nix:
name: "Build Hyprland (Nix)" name: "Build Hyprland (Nix)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
package:
- default
- hyprland-no-hidpi
steps: steps:
- name: Clone repository - name: Clone repository
uses: actions/checkout@v3 uses: actions/checkout@v3
@@ -22,4 +27,4 @@ jobs:
name: hyprland name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Build Hyprland with default settings - name: Build Hyprland with default settings
run: nix build --print-build-logs run: nix build .#${{ matrix.package }} --print-build-logs

6
.gitignore vendored
View File

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

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,38 @@ 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"
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 ) add_compile_options(-std=c++23 -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 +67,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,6 +84,8 @@ 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)
target_link_libraries(Hyprland target_link_libraries(Hyprland
@@ -90,7 +99,9 @@ target_link_libraries(Hyprland
) )
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Setting debug flags")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg -no-pie -fno-builtin") 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_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") 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) ENDIF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)

View File

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

View File

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

46
docs/Hyprland.1 Normal file
View File

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

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.

145
docs/hyprctl.1 Normal file
View File

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

2
docs/meson.build Normal file
View File

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

View File

@@ -1,115 +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
# #
monitor=,preferred,0x0,1 # See https://wiki.hyprland.org/Configuring/Monitors/
workspace=DP-1,1 monitor=,preferred,auto,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_layout= kb_layout = us
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.
} }
general { general {
sensitivity=1.0 # for mouse cursor # See https://wiki.hyprland.org/Configuring/Variables/ for more
main_mod=SUPER
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(1affffee)
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, more passes = more resource intensive. blur = yes
# Your blur "amount" is blur_size * blur_passes, but high blur_size (over around 5-ish) will produce artifacts. blur_size = 3
# if you want heavy blur, you need to up the blur_passes. blur_passes = 1
# the more passes, the more you can up the blur_size without noticing artifacts. 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
# example binds # Example windowrule v1
bind=SUPER,Q,exec,kitty # windowrule = float, ^(kitty)$
bind=SUPER,C,killactive, # Example windowrule v2
bind=SUPER,M,exit, # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
bind=SUPER,E,exec,dolphin # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
bind=SUPER,V,togglefloating,
bind=SUPER,R,exec,wofi --show drun -o DP-3
bind=SUPER,P,pseudo,
bind=SUPER,left,movefocus,l
bind=SUPER,right,movefocus,r
bind=SUPER,up,movefocus,u
bind=SUPER,down,movefocus,d
bind=SUPER,1,workspace,1 # See https://wiki.hyprland.org/Configuring/Keywords/ for more
bind=SUPER,2,workspace,2 $mainMod = SUPER
bind=SUPER,3,workspace,3
bind=SUPER,4,workspace,4
bind=SUPER,5,workspace,5
bind=SUPER,6,workspace,6
bind=SUPER,7,workspace,7
bind=SUPER,8,workspace,8
bind=SUPER,9,workspace,9
bind=SUPER,0,workspace,10
bind=ALT,1,movetoworkspace,1 # Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind=ALT,2,movetoworkspace,2 bind = $mainMod, Q, exec, kitty
bind=ALT,3,movetoworkspace,3 bind = $mainMod, C, killactive,
bind=ALT,4,movetoworkspace,4 bind = $mainMod, M, exit,
bind=ALT,5,movetoworkspace,5 bind = $mainMod, E, exec, dolphin
bind=ALT,6,movetoworkspace,6 bind = $mainMod, V, togglefloating,
bind=ALT,7,movetoworkspace,7 bind = $mainMod, R, exec, wofi --show drun
bind=ALT,8,movetoworkspace,8 bind = $mainMod, P, pseudo, # dwindle
bind=ALT,9,movetoworkspace,9 bind = $mainMod, J, togglesplit, # dwindle
bind=ALT,0,movetoworkspace,10
bind=SUPER,mouse_down,workspace,e+1 # Move focus with mainMod + arrow keys
bind=SUPER,mouse_up,workspace,e-1 bind = $mainMod, left, movefocus, l
bind = $mainMod, right, movefocus, r
bind = $mainMod, up, movefocus, u
bind = $mainMod, down, movefocus, d
# Switch workspaces with mainMod + [0-9]
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

12
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1659219666, "lastModified": 1666377499,
"narHash": "sha256-pzYr5fokQPHv7CmUXioOhhzDy/XyWOIXP4LZvv/T7Mk=", "narHash": "sha256-dZZCGvWcxc7oGnUgFVf0UeNHsJ4VhkTM0v5JRe8EwR8=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "7b9be38c7250b22d829ab6effdee90d5e40c6e5c", "rev": "301aada7a64812853f2e2634a530ef5d34505048",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -26,11 +26,11 @@
"flake": false, "flake": false,
"locked": { "locked": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"lastModified": 1658770113, "lastModified": 1666466001,
"narHash": "sha256-VBq9vw0hvQPKGKLNKLJS8xsUHvrX0o2LUDBVolixenE=", "narHash": "sha256-ZjxAnqtcGmHQHKL1Z9sIraDnzIqrJleWcJXfPtzAm74=",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "7b5e890e61a27375725068a7d1884b26851b3102", "rev": "c2d2773df57750081b16d56da13b5015d752cbd7",
"type": "gitlab" "type": "gitlab"
}, },
"original": { "original": {

View File

@@ -17,26 +17,42 @@
inherit (nixpkgs) lib; inherit (nixpkgs) lib;
genSystems = lib.genAttrs [ genSystems = lib.genAttrs [
# Add more systems if they are supported # Add more systems if they are supported
"aarch64-linux"
"x86_64-linux" "x86_64-linux"
]; ];
pkgsFor = nixpkgs.legacyPackages;
pkgsFor = genSystems (system: import nixpkgs {
inherit system;
overlays = [(_: prev: {
wayland-protocols = prev.wayland-protocols.overrideAttrs (old: rec {
version = "1.27";
src = prev.fetchurl {
url = "https://gitlab.freedesktop.org/wayland/${old.pname}/-/releases/${version}/downloads/${old.pname}-${version}.tar.xz";
hash = "sha256-kEbxCkJdTioAlloDrPtrP7V1pWUDrHLCuGghxpZTN1w=";
};
});
})];
});
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 {
wlroots-hyprland = prev.wlroots.overrideAttrs (__: { wlroots-hyprland = prev.callPackage ./nix/wlroots.nix {
version = mkDate (inputs.wlroots.lastModifiedDate or "19700101"); version = mkDate (inputs.wlroots.lastModifiedDate or "19700101") + "_" + (inputs.wlroots.shortRev or "dirty");
src = inputs.wlroots; src = inputs.wlroots;
}); };
hyprland = prev.callPackage ./nix/default.nix { hyprland = prev.callPackage ./nix/default.nix {
stdenv = prev.gcc12Stdenv; stdenv = prev.gcc12Stdenv;
version = "0.9.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")); version = "0.16.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
wlroots = wlroots-hyprland; wlroots = wlroots-hyprland;
}; };
hyprland-debug = hyprland.override {debug = true;}; hyprland-debug = hyprland.override {debug = true;};
hyprland-no-hidpi = hyprland.override {hidpiXWayland = false;};
waybar-hyprland = prev.waybar.overrideAttrs (oldAttrs: { waybar-hyprland = prev.waybar.overrideAttrs (oldAttrs: {
mesonFlags = oldAttrs.mesonFlags ++ ["-Dexperimental=true"]; mesonFlags = oldAttrs.mesonFlags ++ ["-Dexperimental=true"];
}); });
@@ -62,7 +78,10 @@
nixosModules.default = import ./nix/module.nix self; nixosModules.default = import ./nix/module.nix self;
homeManagerModules.default = import ./nix/hm-module.nix self; homeManagerModules.default = import ./nix/hm-module.nix self;
};
overlay = throw "Hyprland: .overlay output is deprecated, please use the .overlays.default output"; nixConfig = {
extra-substituters = ["https://hyprland.cachix.org"];
extra-trusted-public-keys = ["hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="];
}; };
} }

View File

@@ -19,7 +19,7 @@
#include <deque> #include <deque>
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args] const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
commands: commands:
monitors monitors
workspaces workspaces
@@ -34,7 +34,10 @@ commands:
splash splash
hyprpaper hyprpaper
reload reload
setcursor
getoption
cursorpos
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 ';'
@@ -48,12 +51,6 @@ void request(std::string arg) {
return; return;
} }
const auto SERVER = gethostbyname("localhost");
if (!SERVER) {
std::cout << "Couldn't get host (2)";
return;
}
// get the instance signature // get the instance signature
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE"); auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
@@ -84,6 +81,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);
@@ -93,9 +91,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) {
@@ -149,43 +158,68 @@ 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(argv[2]) + " " + std::string(argv[3]); std::string rq = "/dispatch";
for(int i = 2; i < argc; i++)
rq += " " + std::string(argv[i]);
request(rq); request(rq);
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(argv[2]) + " " + std::string(argv[3]); std::string rq = "/keyword";
for(int i = 2; i < argc; i++)
rq += " " + std::string(argv[i]);
request(rq); request(rq);
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;
}
int setcursorRequest(int argc, char** argv) {
if (argc < 4) {
std::cout << "Usage: hyprctl setcursor <theme> <size>\n\
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]);
request(rq);
return 0;
} }
void batchRequest(std::string arg) { void batchRequest(std::string arg) {
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1); std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
request(rq); request(rq);
} }
@@ -240,6 +274,8 @@ int main(int argc, char** argv) {
fullRequest.pop_back(); // remove trailing space fullRequest.pop_back(); // remove trailing space
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);
@@ -252,9 +288,12 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/splash")) request(fullRequest); else if (fullRequest.contains("/splash")) request(fullRequest);
else if (fullRequest.contains("/devices")) request(fullRequest); else if (fullRequest.contains("/devices")) request(fullRequest);
else if (fullRequest.contains("/reload")) request(fullRequest); else if (fullRequest.contains("/reload")) request(fullRequest);
else if (fullRequest.contains("/dispatch")) dispatchRequest(argc, argv); else if (fullRequest.contains("/getoption")) request(fullRequest);
else if (fullRequest.contains("/keyword")) keywordRequest(argc, argv); else if (fullRequest.contains("/cursorpos")) request(fullRequest);
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());
@@ -262,5 +301,5 @@ int main(int argc, char** argv) {
} }
printf("\n"); printf("\n");
return 0; return exitStatus;
} }

View File

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

View File

@@ -2,6 +2,7 @@
lib, lib,
stdenv, stdenv,
fetchFromGitHub, fetchFromGitHub,
fetchpatch,
pkg-config, pkg-config,
meson, meson,
ninja, ninja,
@@ -21,64 +22,85 @@
xwayland, xwayland,
debug ? false, debug ? false,
enableXWayland ? true, enableXWayland ? true,
hidpiXWayland ? true,
legacyRenderer ? false, legacyRenderer ? false,
nvidiaPatches ? false,
version ? "git", version ? "git",
}: }: let
stdenv.mkDerivation { assertXWayland = lib.assertMsg (hidpiXWayland -> enableXWayland) ''
pname = "hyprland" + lib.optionalString debug "-debug"; Hyprland: cannot have hidpiXWayland when enableXWayland is false.
inherit version;
src = ../.;
nativeBuildInputs = [
meson
ninja
pkg-config
];
buildInputs =
[
git
libdrm
libinput
libxcb
libxkbcommon
mesa
pango
wayland
wayland-protocols
wayland-scanner
(wlroots.override {inherit enableXWayland;})
xcbutilwm
]
++ lib.optional enableXWayland xwayland;
mesonBuildType =
if debug
then "debug"
else "release";
mesonFlags = builtins.concatLists [
(lib.optional (!enableXWayland) "-DNO_XWAYLAND=true")
(lib.optional (legacyRenderer) "-DLEGACY_RENDERER:STRING=true")
];
patches = [
# make meson use the provided wlroots instead of the git submodule
./meson-build.patch
];
# Fix hardcoded paths to /usr installation
postPatch = ''
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
''; '';
in
assert assertXWayland;
stdenv.mkDerivation {
pname = "hyprland" + lib.optionalString debug "-debug";
inherit version;
passthru.providedSessions = ["hyprland"]; src = lib.cleanSourceWith {
filter = name: type: let
baseName = baseNameOf (toString name);
in
! (
lib.hasSuffix ".nix" baseName
);
src = lib.cleanSource ../.;
};
meta = with lib; { nativeBuildInputs = [
homepage = "https://github.com/vaxerski/Hyprland"; meson
description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; ninja
license = licenses.bsd3; pkg-config
platforms = platforms.linux; ];
mainProgram = "Hyprland";
}; outputs = [
} "out"
"man"
];
buildInputs =
[
git
libdrm
libinput
libxcb
libxkbcommon
mesa
pango
wayland
wayland-protocols
wayland-scanner
(wlroots.override {inherit enableXWayland hidpiXWayland nvidiaPatches;})
xcbutilwm
]
++ lib.optional enableXWayland xwayland;
mesonBuildType =
if debug
then "debug"
else "release";
mesonFlags = builtins.concatLists [
(lib.optional (!enableXWayland) "-Dxwayland=disabled")
(lib.optional legacyRenderer "-DLEGACY_RENDERER:STRING=true")
];
patches = [
# make meson use the provided wlroots instead of the git submodule
./meson-build.patch
];
# Fix hardcoded paths to /usr installation
postPatch = ''
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
'';
passthru.providedSessions = ["hyprland"];
meta = with lib; {
homepage = "https://github.com/vaxerski/Hyprland";
description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
license = licenses.bsd3;
platforms = platforms.linux;
mainProgram = "Hyprland";
};
}

View File

@@ -6,7 +6,8 @@ self: {
}: let }: let
cfg = config.wayland.windowManager.hyprland; cfg = config.wayland.windowManager.hyprland;
defaultHyprlandPackage = self.packages.${pkgs.system}.default.override { defaultHyprlandPackage = self.packages.${pkgs.system}.default.override {
enableXWayland = cfg.xwayland; enableXWayland = cfg.xwayland.enable;
hidpiXWayland = cfg.xwayland.hidpi;
}; };
in { in {
options.wayland.windowManager.hyprland = { options.wayland.windowManager.hyprland = {
@@ -41,12 +42,21 @@ in {
</itemizedlist> </itemizedlist>
''; '';
}; };
xwayland = lib.mkOption { xwayland = {
type = lib.types.bool; enable = lib.mkOption {
default = true; type = lib.types.bool;
description = '' default = true;
Enable xwayland. description = ''
''; Enable XWayland.
'';
};
hidpi = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Enable HiDPI XWayland.
'';
};
}; };
extraConfig = lib.mkOption { extraConfig = lib.mkOption {
@@ -56,18 +66,45 @@ in {
Extra configuration lines to add to ~/.config/hypr/hyprland.conf. Extra configuration lines to add to ~/.config/hypr/hyprland.conf.
''; '';
}; };
recommendedEnvironment = lib.mkOption {
type = lib.types.bool;
default = true;
defaultText = lib.literalExpression "true";
example = lib.literalExpression "false";
description = ''
Whether to set the recommended environment variables.
'';
};
imports = [
(
lib.mkRenamedOptionModule
["wayland" "windowManager" "hyprland" "xwayland"]
["wayland" "windowManager" "hyprland" "xwayland" "enable"]
)
];
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home.packages = home.packages =
lib.optional (cfg.package != null) cfg.package lib.optional (cfg.package != null) cfg.package
++ lib.optional cfg.xwayland pkgs.xwayland; ++ lib.optional cfg.xwayland.enable pkgs.xwayland;
home.sessionVariables = lib.mkIf cfg.recommendedEnvironment {
GDK_BACKEND = "wayland,x11";
_JAVA_AWT_WM_NONREPARENTING = "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; systemctl --user start hyprland-session.target exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP
") exec-once=systemctl --user start hyprland-session.target
'')
+ cfg.extraConfig; + cfg.extraConfig;
onChange = let onChange = let
@@ -75,7 +112,7 @@ in {
if cfg.package == null if cfg.package == null
then defaultHyprlandPackage then defaultHyprlandPackage
else cfg.package; else cfg.package;
in "${hyprlandPackage}/bin/hyprctl reload"; in "HYPRLAND_INSTANCE_SIGNATURE=$(ls -w 1 /tmp/hypr | tail -1) ${hyprlandPackage}/bin/hyprctl reload config-only";
}; };
systemd.user.targets.hyprland-session = lib.mkIf cfg.systemdIntegration { systemd.user.targets.hyprland-session = lib.mkIf cfg.systemdIntegration {

View File

@@ -8,6 +8,10 @@ self: {
with lib; let with lib; let
cfg = config.programs.hyprland; cfg = config.programs.hyprland;
in { in {
imports = [
(mkRemovedOptionModule ["programs" "hyprland" "extraPackages"] "extraPackages has been removed. Use environment.systemPackages instead.")
];
options.programs.hyprland = { options.programs.hyprland = {
enable = mkEnableOption '' enable = mkEnableOption ''
Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks. Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
@@ -27,20 +31,40 @@ in {
''; '';
}; };
imports = [ recommendedEnvironment = mkOption {
(mkRemovedOptionModule ["programs" "hyprland" "extraPackages"] "extraPackages has been removed. Use environment.systemPackages instead.") type = types.bool;
]; default = true;
defaultText = literalExpression "true";
example = literalExpression "false";
description = ''
Whether to set the recommended environment variables.
'';
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = lib.optional (cfg.package != null) cfg.package; environment = {
security.polkit.enable = true; systemPackages = lib.optional (cfg.package != null) cfg.package;
hardware.opengl.enable = mkDefault true;
sessionVariables = mkIf cfg.recommendedEnvironment {
GDK_BACKEND = "wayland,x11";
_JAVA_AWT_WM_NONREPARENTING = "1";
NIXOS_OZONE_WL = "1";
XCURSOR_SIZE = "24";
XDG_SESSION_TYPE = "wayland";
};
};
fonts.enableDefaultFonts = mkDefault true; fonts.enableDefaultFonts = mkDefault true;
programs.dconf.enable = mkDefault true; hardware.opengl.enable = mkDefault true;
programs = {
dconf.enable = mkDefault true;
xwayland.enable = mkDefault 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) cfg.package;
programs.xwayland.enable = mkDefault true; xdg.portal = {
xdg.portal.enable = mkDefault true; enable = mkDefault true;
xdg.portal.extraPortals = [pkgs.xdg-desktop-portal-wlr]; extraPortals = [pkgs.xdg-desktop-portal-wlr];
};
}; };
} }

64
nix/wlroots.nix Normal file
View File

@@ -0,0 +1,64 @@
{
version,
src,
#
wlroots,
xwayland,
fetchpatch,
lib,
hidpiXWayland ? true,
enableXWayland ? true,
nvidiaPatches ? false,
}:
assert (lib.assertMsg (hidpiXWayland -> enableXWayland) ''
wlroots-hyprland: cannot have hidpiXWayland when enableXWayland is false.
'');
(wlroots.overrideAttrs
(old: {
inherit version src;
pname =
old.pname
+ "-hyprland"
+ (
if hidpiXWayland
then "-hidpi"
else ""
)
+ (
if nvidiaPatches
then "-nvidia"
else ""
);
patches =
(old.patches or [])
++ (lib.optionals (enableXWayland && hidpiXWayland) [
(fetchpatch {
url = "https://gitlab.freedesktop.org/lilydjwg/wlroots/-/commit/6c5ffcd1fee9e44780a6a8792f74ecfbe24a1ca7.diff";
sha256 = "sha256-Eo1pTa/PIiJsRZwIUnHGTIFFIedzODVf0ZeuXb0a3TQ=";
})
(fetchpatch {
url = "https://gitlab.freedesktop.org/wlroots/wlroots/-/commit/18595000f3a21502fd60bf213122859cc348f9af.diff";
sha256 = "sha256-jvfkAMh3gzkfuoRhB4E9T5X1Hu62wgUjj4tZkJm0mrI=";
revert = true;
})
]);
postPatch =
(old.postPatch or "")
+ (
if nvidiaPatches
then ''
substituteInPlace render/gles2/renderer.c --replace "glFlush();" "glFinish();"
''
else ""
);
}))
.override {
xwayland = xwayland.overrideAttrs (old: {
patches =
(old.patches or [])
++ (lib.optionals hidpiXWayland [
./xwayland-vsync.patch
./xwayland-hidpi.patch
]);
});
}

498
nix/xwayland-hidpi.patch Normal file
View File

@@ -0,0 +1,498 @@
diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index c4457cc2a61b2103b47f996b51dbbe9eb87bd715..4a33e1f33e73c35c1691564ef4852e7501b02245 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -171,6 +171,8 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
}
wl_surface_attach(xwl_cursor->surface, buffer, 0, 0);
+ wl_surface_set_buffer_scale(xwl_cursor->surface,
+ xwl_seat->xwl_screen->global_output_scale);
xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0,
xwl_seat->x_cursor->bits->width,
xwl_seat->x_cursor->bits->height);
@@ -190,6 +192,7 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
void
xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
{
+ struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
struct xwl_cursor *xwl_cursor = &xwl_seat->cursor;
PixmapPtr pixmap;
CursorPtr cursor;
@@ -220,8 +223,8 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
wl_pointer_set_cursor(xwl_seat->wl_pointer,
xwl_seat->pointer_enter_serial,
xwl_cursor->surface,
- xwl_seat->x_cursor->bits->xhot,
- xwl_seat->x_cursor->bits->yhot);
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->xhot),
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->yhot));
xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
}
@@ -230,6 +233,7 @@ void
xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
{
struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
+ struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor;
PixmapPtr pixmap;
CursorPtr cursor;
@@ -258,9 +262,9 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
xwl_tablet_tool->proximity_in_serial,
xwl_cursor->surface,
- xwl_seat->x_cursor->bits->xhot,
- xwl_seat->x_cursor->bits->yhot);
-
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->xhot),
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->yhot));
+ wl_surface_set_buffer_scale(xwl_cursor->surface, xwl_screen->global_output_scale);
xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
}
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf129b5e17a 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -412,8 +412,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
DeviceIntPtr dev = get_pointer_device(xwl_seat);
DeviceIntPtr master;
int i;
- int sx = wl_fixed_to_int(sx_w);
- int sy = wl_fixed_to_int(sy_w);
+ int sx = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;
+ int sy = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;
int dx, dy;
ScreenPtr pScreen = xwl_seat->xwl_screen->screen;
ValuatorMask mask;
@@ -592,13 +592,14 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
{
struct xwl_seat *xwl_seat = data;
+ int32_t scale = xwl_seat->xwl_screen->global_output_scale;
if (!xwl_seat->focus_window)
return;
xwl_seat->pending_pointer_event.has_absolute = TRUE;
- xwl_seat->pending_pointer_event.x = sx_w;
- xwl_seat->pending_pointer_event.y = sy_w;
+ xwl_seat->pending_pointer_event.x = sx_w * scale;
+ xwl_seat->pending_pointer_event.y = sy_w * scale;
if (wl_proxy_get_version((struct wl_proxy *) xwl_seat->wl_pointer) < 5)
dispatch_pointer_motion_event(xwl_seat);
@@ -672,7 +673,8 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
xorg_list_del(&pending->l);
free(pending);
} else {
- valuator_mask_set_double(&mask, index, wl_fixed_to_double(value) / divisor);
+ double scaled_value = wl_fixed_to_double(value);
+ valuator_mask_set_double(&mask, index, scaled_value / divisor);
}
QueuePointerEvents(get_pointer_device(xwl_seat),
@@ -740,12 +742,13 @@ relative_pointer_handle_relative_motion(void *data,
wl_fixed_t dy_unaccelf)
{
struct xwl_seat *xwl_seat = data;
+ int32_t scale = xwl_seat->xwl_screen->global_output_scale;
xwl_seat->pending_pointer_event.has_relative = TRUE;
- xwl_seat->pending_pointer_event.dx = wl_fixed_to_double(dxf);
- xwl_seat->pending_pointer_event.dy = wl_fixed_to_double(dyf);
- xwl_seat->pending_pointer_event.dx_unaccel = wl_fixed_to_double(dx_unaccelf);
- xwl_seat->pending_pointer_event.dy_unaccel = wl_fixed_to_double(dy_unaccelf);
+ xwl_seat->pending_pointer_event.dx = wl_fixed_to_double(dxf) * scale;
+ xwl_seat->pending_pointer_event.dy = wl_fixed_to_double(dyf) * scale;
+ xwl_seat->pending_pointer_event.dx_unaccel = wl_fixed_to_double(dx_unaccelf) * scale;
+ xwl_seat->pending_pointer_event.dy_unaccel = wl_fixed_to_double(dy_unaccelf) * scale;
if (!xwl_seat->focus_window)
return;
@@ -1057,8 +1060,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
xwl_touch->window = wl_surface_get_user_data(surface);
xwl_touch->id = id;
- xwl_touch->x = wl_fixed_to_int(sx_w);
- xwl_touch->y = wl_fixed_to_int(sy_w);
+ xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;
+ xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;
xorg_list_add(&xwl_touch->link_touch, &xwl_seat->touches);
xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchBegin);
@@ -1094,8 +1097,8 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch,
if (!xwl_touch)
return;
- xwl_touch->x = wl_fixed_to_int(sx_w);
- xwl_touch->y = wl_fixed_to_int(sy_w);
+ xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;;
+ xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;;
xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchUpdate);
}
@@ -1726,8 +1729,8 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
struct xwl_tablet_tool *xwl_tablet_tool = data;
struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
int32_t dx, dy;
- double sx = wl_fixed_to_double(x);
- double sy = wl_fixed_to_double(y);
+ double sx = wl_fixed_to_double(x) * xwl_seat->xwl_screen->global_output_scale;
+ double sy = wl_fixed_to_double(y) * xwl_seat->xwl_screen->global_output_scale;
if (!xwl_seat->tablet_focus_window)
return;
@@ -2714,6 +2717,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
int x,
int y)
{
+ struct xwl_screen *xwl_screen;
struct zwp_locked_pointer_v1 *locked_pointer =
warp_emulator->locked_pointer;
WindowPtr window;
@@ -2725,6 +2729,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
if (!warp_emulator->xwl_seat->focus_window)
return;
+ xwl_screen = warp_emulator->xwl_seat->xwl_screen;
window = warp_emulator->xwl_seat->focus_window->window;
if (x >= window->drawable.x ||
y >= window->drawable.y ||
@@ -2733,8 +2738,8 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
sx = x - window->drawable.x;
sy = y - window->drawable.y;
zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer,
- wl_fixed_from_int(sx),
- wl_fixed_from_int(sy));
+ wl_fixed_from_int(xwl_scale_to(xwl_screen, sx)),
+ wl_fixed_from_int(xwl_scale_to(xwl_screen, sy)));
wl_surface_commit(warp_emulator->xwl_seat->focus_window->surface);
}
}
diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
index ef705bc01bf8c2d2f170cda9ba21ed8293f50559..b8f6cd51bd240ed5e16271eb4749db18868bea7b 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -191,6 +191,9 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height)
{
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
+ width *= xwl_screen->global_output_scale;
+ height *= xwl_screen->global_output_scale;
+
if (xwl_screen->root_clip_mode == ROOT_CLIP_FULL)
SetRootClip(xwl_screen->screen, ROOT_CLIP_NONE);
@@ -497,14 +500,15 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
xwl_output_set_randr_emu_props(xwl_output->xwl_screen, client);
}
-static void
-apply_output_change(struct xwl_output *xwl_output)
+void
+xwl_output_apply_changes(struct xwl_output *xwl_output)
{
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
struct xwl_output *it;
int mode_width, mode_height, count;
int width = 0, height = 0, has_this_output = 0;
RRModePtr *randr_modes;
+ int32_t scale = xwl_screen->global_output_scale;
/* Clear out the "done" received flags */
xwl_output->wl_output_done = FALSE;
@@ -523,10 +527,10 @@ apply_output_change(struct xwl_output *xwl_output)
}
/* Build a fresh modes array using the current refresh rate */
- randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count);
+ randr_modes = output_get_rr_modes(xwl_output, mode_width * scale, mode_height * scale, &count);
RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1);
RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0],
- xwl_output->x, xwl_output->y,
+ xwl_output->x * scale, xwl_output->y * scale,
xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
/* RROutputSetModes takes ownership of the passed in modes, so we only
* have to free the pointer array.
@@ -567,7 +571,7 @@ output_handle_done(void *data, struct wl_output *wl_output)
*/
if (xwl_output->xdg_output_done || !xwl_output->xdg_output ||
zxdg_output_v1_get_version(xwl_output->xdg_output) >= 3)
- apply_output_change(xwl_output);
+ xwl_output_apply_changes(xwl_output);
}
static void
@@ -610,7 +614,7 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
xwl_output->xdg_output_done = TRUE;
if (xwl_output->wl_output_done &&
zxdg_output_v1_get_version(xdg_output) < 3)
- apply_output_change(xwl_output);
+ xwl_output_apply_changes(xwl_output);
}
static void
@@ -678,6 +682,8 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
RROutputSetConnection(xwl_output->randr_output, RR_Connected);
RRTellChanged(xwl_screen->screen);
+ xwl_output->scale = 1;
+
/* We want the output to be in the list as soon as created so we can
* use it when binding to the xdg-output protocol...
*/
diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h
index 02b9831083e82a33d85d4404e39d00f06f6c56fd..ec089757f44178dcd7f9c48907f790ce1b2a2729 100644
--- a/hw/xwayland/xwayland-output.h
+++ b/hw/xwayland/xwayland-output.h
@@ -53,7 +53,7 @@ struct xwl_output {
struct wl_output *output;
struct zxdg_output_v1 *xdg_output;
uint32_t server_output_id;
- int32_t x, y, width, height, refresh;
+ int32_t x, y, width, height, refresh, scale;
Rotation rotation;
Bool wl_output_done;
Bool xdg_output_done;
@@ -100,6 +100,8 @@ void xwl_output_set_emulated_mode(struct xwl_output *xwl_output,
void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
WindowPtr window);
+void xwl_output_apply_changes(struct xwl_output *xwl_output);
+
void xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen);
#endif /* XWAYLAND_OUTPUT_H */
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index c9cf8c2f569a319034e0789e7587414e50237065..5be0c208ca46b1a53a136885fdc8ab44251fe7ff 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -680,6 +680,8 @@ xwl_present_flip(WindowPtr present_window,
/* We can flip directly to the main surface (full screen window without clips) */
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
+ wl_surface_set_buffer_scale(xwl_window->surface,
+ xwl_window->xwl_screen->global_output_scale);
if (!xwl_window->frame_callback)
xwl_window_create_frame_callback(xwl_window);
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f417925f0f8 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -51,6 +51,7 @@
#include "xwayland-pixmap.h"
#include "xwayland-present.h"
#include "xwayland-shm.h"
+#include "xwayland-window-buffers.h"
#ifdef MITSHM
#include "shmint.h"
@@ -110,6 +111,12 @@ xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen)
return xwl_screen->rootless && xwl_screen_has_viewport_support(xwl_screen);
}
+int
+xwl_scale_to(struct xwl_screen *xwl_screen, int value)
+{
+ return value / (double)xwl_screen->global_output_scale + 0.5;
+}
+
/* Return the output @ 0x0, falling back to the first output in the list */
struct xwl_output *
xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
@@ -127,6 +134,37 @@ xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
return xorg_list_first_entry(&xwl_screen->output_list, struct xwl_output, link);
}
+static void
+xwl_screen_set_global_scale_from_property(struct xwl_screen *screen,
+ PropertyPtr prop)
+{
+ CARD32 *propdata;
+
+ if (prop->type != XA_CARDINAL || prop->format != 32 || prop->size != 1) {
+ // TODO: handle warnings more cleanly.
+ LogMessageVerb(X_WARNING, 0, "Bad value for property %s.\n",
+ NameForAtom(prop->propertyName));
+ return;
+ }
+
+ propdata = prop->data;
+ xwl_screen_set_global_scale(screen, propdata[0]);
+}
+
+static void
+xwl_screen_update_property(struct xwl_screen *screen,
+ PropertyStateRec *propstate)
+{
+ switch (propstate->state) {
+ case PropertyNewValue:
+ xwl_screen_set_global_scale_from_property(screen, propstate->prop);
+ break;
+ case PropertyDelete:
+ xwl_screen_set_global_scale(screen, 1);
+ break;
+ }
+}
+
static void
xwl_property_callback(CallbackListPtr *pcbl, void *closure,
void *calldata)
@@ -134,19 +172,24 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure,
ScreenPtr screen = closure;
PropertyStateRec *rec = calldata;
struct xwl_screen *xwl_screen;
- struct xwl_window *xwl_window;
if (rec->win->drawable.pScreen != screen)
return;
- xwl_window = xwl_window_get(rec->win);
- if (!xwl_window)
- return;
-
xwl_screen = xwl_screen_get(screen);
- if (rec->prop->propertyName == xwl_screen->allow_commits_prop)
+ if (rec->prop->propertyName == xwl_screen->allow_commits_prop) {
+ struct xwl_window *xwl_window;
+
+ xwl_window = xwl_window_get(rec->win);
+ if (!xwl_window)
+ return;
+
xwl_window_update_property(xwl_window, rec);
+ }
+ else if (rec->prop->propertyName == xwl_screen->global_output_scale_prop) {
+ xwl_screen_update_property(xwl_screen, rec);
+ }
}
Bool
@@ -521,8 +564,14 @@ void xwl_surface_damage(struct xwl_screen *xwl_screen,
{
if (wl_surface_get_version(surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
wl_surface_damage_buffer(surface, x, y, width, height);
- else
+ else {
+ x = xwl_scale_to(xwl_screen, x);
+ y = xwl_scale_to(xwl_screen, y);
+ width = xwl_scale_to(xwl_screen, width);
+ height = xwl_scale_to(xwl_screen, height);
+
wl_surface_damage(surface, x, y, width, height);
+ }
}
void
@@ -538,10 +587,34 @@ xwl_screen_roundtrip(struct xwl_screen *xwl_screen)
xwl_give_up("could not connect to wayland server\n");
}
+void
+xwl_screen_set_global_scale(struct xwl_screen *xwl_screen, int32_t scale)
+{
+ struct xwl_output *it;
+ struct xwl_window *xwl_window;
+
+ xwl_screen->global_output_scale = scale;
+
+ /* change randr resolutions and positions */
+ xorg_list_for_each_entry(it, &xwl_screen->output_list, link) {
+ xwl_output_apply_changes(it);
+ }
+
+ if (!xwl_screen->rootless && xwl_screen->screen->root) {
+ /* Clear all the buffers, so that they'll be remade with the new sizes
+ * (this doesn't occur automatically because as far as Xorg is
+ * concerned, the window's size is the same) */
+ xorg_list_for_each_entry(xwl_window, &xwl_screen->window_list, link_window) {
+ xwl_window_buffers_recycle(xwl_window);
+ }
+ }
+}
+
Bool
xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
{
static const char allow_commits[] = "_XWAYLAND_ALLOW_COMMITS";
+ static const char global_output_scale[] = "_XWAYLAND_GLOBAL_OUTPUT_SCALE";
struct xwl_screen *xwl_screen;
Pixel red_mask, blue_mask, green_mask;
int ret, bpc, green_bpc, i;
@@ -573,6 +646,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
#ifdef XWL_HAS_GLAMOR
xwl_screen->glamor = 1;
#endif
+ xwl_screen->global_output_scale = 1;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-rootless") == 0) {
@@ -743,6 +817,12 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
if (xwl_screen->allow_commits_prop == BAD_RESOURCE)
return FALSE;
+ xwl_screen->global_output_scale_prop = MakeAtom(global_output_scale,
+ strlen(global_output_scale),
+ TRUE);
+ if (xwl_screen->global_output_scale_prop == BAD_RESOURCE)
+ return FALSE;
+
AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen);
xwl_screen_roundtrip(xwl_screen);
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index b965dddd7f964b1d100bbb9d10da1c35ab39810e..7446829d098fbe235e605084a016daff1a8eaea2 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -72,6 +72,8 @@ struct xwl_screen {
struct xorg_list damage_window_list;
struct xorg_list window_list;
+ int32_t global_output_scale;
+
int wayland_fd;
struct wl_display *display;
struct wl_registry *registry;
@@ -107,6 +109,7 @@ struct xwl_screen {
struct glamor_context *glamor_ctx;
Atom allow_commits_prop;
+ Atom global_output_scale_prop;
/* The preferred GLVND vendor. If NULL, "mesa" is assumed. */
const char *glvnd_vendor;
@@ -134,5 +137,7 @@ void xwl_screen_roundtrip (struct xwl_screen *xwl_screen);
void xwl_surface_damage(struct xwl_screen *xwl_screen,
struct wl_surface *surface,
int32_t x, int32_t y, int32_t width, int32_t height);
+int xwl_scale_to(struct xwl_screen *xwl_screen, int value);
+void xwl_screen_set_global_scale(struct xwl_screen *xwl_screen, int32_t scale);
#endif /* XWAYLAND_SCREEN_H */
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 00f161eda084e335ac07471a2198176d75d9fcf0..ed3903853f0dab1dad390cd8429639541546157d 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -470,7 +470,8 @@ ensure_surface_for_window(WindowPtr window)
}
wl_region_add(region, 0, 0,
- window->drawable.width, window->drawable.height);
+ xwl_scale_to(xwl_screen, window->drawable.width),
+ xwl_scale_to(xwl_screen, window->drawable.height));
wl_surface_set_opaque_region(xwl_window->surface, region);
wl_region_destroy(region);
}
@@ -820,6 +821,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
#endif
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
+ wl_surface_set_buffer_scale(xwl_window->surface, xwl_screen->global_output_scale);
/* Arbitrary limit to try to avoid flooding the Wayland
* connection. If we flood it too much anyway, this could

12
nix/xwayland-vsync.patch Normal file
View File

@@ -0,0 +1,12 @@
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -824,7 +824,8 @@
dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
vblank->pixmap = NULL;
- if (xwl_present_queue_vblank(screen, window, vblank->crtc,
+ if (vblank->target_msc > crtc_msc &&
+ xwl_present_queue_vblank(screen, window, vblank->crtc,
vblank->event_id, crtc_msc + 1)
== Success)
return;

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,8 @@ public:
wlr_compositor* m_sWLRCompositor; wlr_compositor* m_sWLRCompositor;
wlr_subcompositor* m_sWLRSubCompositor; wlr_subcompositor* m_sWLRSubCompositor;
wlr_data_device_manager* m_sWLRDataDevMgr; wlr_data_device_manager* m_sWLRDataDevMgr;
wlr_drm* m_sWRLDRM;
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_xdg_activation_v1* m_sWLRXDGActivation; wlr_xdg_activation_v1* m_sWLRXDGActivation;
wlr_output_layout* m_sWLROutputLayout; wlr_output_layout* m_sWLROutputLayout;
wlr_idle* m_sWLRIdle; wlr_idle* m_sWLRIdle;
@@ -54,7 +56,6 @@ public:
wlr_egl* m_sWLREGL; wlr_egl* m_sWLREGL;
int m_iDRMFD; int m_iDRMFD;
wlr_ext_workspace_manager_v1* m_sWLREXTWorkspaceMgr; wlr_ext_workspace_manager_v1* m_sWLREXTWorkspaceMgr;
wlr_linux_dmabuf_v1* m_sWLRDmabuf;
wlr_pointer_constraints_v1* m_sWLRPointerConstraints; wlr_pointer_constraints_v1* m_sWLRPointerConstraints;
wlr_relative_pointer_manager_v1* m_sWLRRelPointerMgr; wlr_relative_pointer_manager_v1* m_sWLRRelPointerMgr;
wlr_server_decoration_manager* m_sWLRServerDecoMgr; wlr_server_decoration_manager* m_sWLRServerDecoMgr;
@@ -66,12 +67,15 @@ public:
wlr_idle_inhibit_manager_v1* m_sWLRIdleInhibitMgr; wlr_idle_inhibit_manager_v1* m_sWLRIdleInhibitMgr;
wlr_pointer_gestures_v1* m_sWLRPointerGestures; wlr_pointer_gestures_v1* m_sWLRPointerGestures;
wlr_output_power_manager_v1* m_sWLROutputPowerMgr; wlr_output_power_manager_v1* m_sWLROutputPowerMgr;
wlr_input_method_manager_v2* m_sWLRIMEMgr;
wlr_text_input_manager_v3* m_sWLRTextInputMgr;
wlr_xdg_activation_v1* m_sWLRActivation;
// ------------------------------------------------- // // ------------------------------------------------- //
const char* m_szWLDisplaySocket; const char* 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
@@ -83,18 +87,21 @@ public:
std::vector<CWindow*> m_vWindowsFadingOut; std::vector<CWindow*> m_vWindowsFadingOut;
std::vector<SLayerSurface*> m_vSurfacesFadingOut; std::vector<SLayerSurface*> m_vSurfacesFadingOut;
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_bIsShuttingDown = false;
std::deque<uint64_t> m_dProcessPIDsOnShutdown; // stores PIDs of apps to kill later when shutting down
// ------------------------------------------------- // // ------------------------------------------------- //
@@ -125,7 +132,6 @@ public:
void updateWorkspaceWindowDecos(const int&); void updateWorkspaceWindowDecos(const int&);
int getWindowsOnWorkspace(const int&); int getWindowsOnWorkspace(const int&);
CWindow* getFirstWindowOnWorkspace(const int&); CWindow* getFirstWindowOnWorkspace(const int&);
void fixXWaylandWindowsOnWorkspace(const int&);
CWindow* getFullscreenWindowOnWorkspace(const int&); CWindow* getFullscreenWindowOnWorkspace(const int&);
bool doesSeatAcceptInput(wlr_surface*); bool doesSeatAcceptInput(wlr_surface*);
bool isWindowActive(CWindow*); bool isWindowActive(CWindow*);
@@ -133,17 +139,18 @@ public:
void cleanupFadingOut(const int& monid); void cleanupFadingOut(const int& monid);
CWindow* getWindowInDirection(CWindow*, char); CWindow* getWindowInDirection(CWindow*, char);
void deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclude = nullptr); void deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclude = nullptr);
CWindow* getNextWindowOnWorkspace(CWindow*); CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false);
CWindow* getPrevWindowOnWorkspace(CWindow*); CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false);
int getNextAvailableNamedWorkspace(); int getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnAnyMonitor(const Vector2D&);
CWindow* getConstraintWindow(SMouse*); CWindow* getConstraintWindow(SMouse*);
CMonitor* getMonitorInDirection(const char&); CMonitor* getMonitorInDirection(const char&);
void updateAllWindowsAnimatedDecorationValues(); void updateAllWindowsAnimatedDecorationValues();
void updateWindowAnimatedDecorationValues(CWindow*); void updateWindowAnimatedDecorationValues(CWindow*);
void moveWindowToWorkspace(CWindow*, const std::string&);
int getNextAvailableMonitorID(); int getNextAvailableMonitorID();
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*); void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int&); bool workspaceIDOutOfBounds(const int&);
void setWindowFullscreen(CWindow*, bool, eFullscreenMode); void setWindowFullscreen(CWindow*, bool, eFullscreenMode);
void moveUnmanagedX11ToWindows(CWindow*); void moveUnmanagedX11ToWindows(CWindow*);
@@ -153,14 +160,21 @@ public:
void addToFadingOutSafe(CWindow*); void addToFadingOutSafe(CWindow*);
CWindow* getWindowByRegex(const std::string&); CWindow* getWindowByRegex(const std::string&);
void warpCursorTo(const Vector2D&); void warpCursorTo(const Vector2D&);
SLayerSurface* getLayerSurfaceFromWlr(wlr_layer_surface_v1*);
SLayerSurface* getLayerSurfaceFromSurface(wlr_surface*);
void closeWindow(CWindow*);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const int&);
bool cursorOnReservedArea();
CWorkspace* createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused!
std::string explicitConfigPath; std::string explicitConfigPath;
void startHyprCtlTick();
private: private:
void initAllSignals(); void initAllSignals();
void setRandomSplash(); void setRandomSplash();
uint64_t m_iHyprlandPID = 0;
}; };
@@ -179,4 +193,4 @@ inline std::map<std::string, xcb_atom_t> HYPRATOMS = {
HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"), HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"),
HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"), HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"),
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"), HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"),
HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION")}; HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION")};

View File

@@ -9,6 +9,7 @@ CWindow::CWindow() {
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);
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
m_dWindowDecorations.emplace_back(std::make_unique<CHyprDropShadowDecoration>(this)); // put the shadow so it's the first deco (has to be rendered first) m_dWindowDecorations.emplace_back(std::make_unique<CHyprDropShadowDecoration>(this)); // put the shadow so it's the first deco (has to be rendered first)
} }
@@ -21,9 +22,9 @@ CWindow::~CWindow() {
} }
wlr_box CWindow::getFullWindowBoundingBox() { wlr_box CWindow::getFullWindowBoundingBox() {
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
SWindowDecorationExtents maxExtents = {{*PBORDERSIZE + 1, *PBORDERSIZE + 1}, {*PBORDERSIZE + 1, *PBORDERSIZE + 1}}; SWindowDecorationExtents maxExtents = {{*PBORDERSIZE + 2, *PBORDERSIZE + 2}, {*PBORDERSIZE + 2, *PBORDERSIZE + 2}};
for (auto& wd : m_dWindowDecorations) { for (auto& wd : m_dWindowDecorations) {
@@ -47,7 +48,7 @@ wlr_box CWindow::getFullWindowBoundingBox() {
m_vRealPosition.vec().y - maxExtents.topLeft.y, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x,
m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y}; m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox; return finalBox;
} }
@@ -96,8 +97,7 @@ void CWindow::updateWindowDecos() {
pid_t CWindow::getPID() { pid_t CWindow::getPID() {
pid_t PID = -1; pid_t PID = -1;
if (!m_bIsX11) { if (!m_bIsX11) {
const auto CLIENT = wl_resource_get_client(m_uSurface.xdg->resource); wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
wl_client_get_credentials(CLIENT, &PID, nullptr, nullptr);
} else { } else {
PID = m_uSurface.xwayland->pid; PID = m_uSurface.xwayland->pid;
} }
@@ -112,4 +112,152 @@ IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) {
} }
return nullptr; return nullptr;
}
void CWindow::createToplevelHandle() {
if (m_bIsX11 && (m_bX11DoesntWantBorders || m_iX11Type == 2))
return; // don't create a toplevel
m_phForeignToplevel = wlr_foreign_toplevel_handle_v1_create(g_pCompositor->m_sWLRToplevelMgr);
wlr_foreign_toplevel_handle_v1_set_app_id(m_phForeignToplevel, g_pXWaylandManager->getAppIDClass(this).c_str());
wlr_foreign_toplevel_handle_v1_output_enter(m_phForeignToplevel, g_pCompositor->getMonitorFromID(m_iMonitorID)->output);
wlr_foreign_toplevel_handle_v1_set_title(m_phForeignToplevel, m_szTitle.c_str());
wlr_foreign_toplevel_handle_v1_set_maximized(m_phForeignToplevel, false);
wlr_foreign_toplevel_handle_v1_set_minimized(m_phForeignToplevel, false);
wlr_foreign_toplevel_handle_v1_set_fullscreen(m_phForeignToplevel, false);
// handle events
hyprListener_toplevelActivate.initCallback(&m_phForeignToplevel->events.request_activate, [&](void* owner, void* data) {
g_pCompositor->focusWindow(this);
}, this, "Toplevel");
hyprListener_toplevelFullscreen.initCallback(&m_phForeignToplevel->events.request_fullscreen, [&](void* owner, void* data) {
const auto EV = (wlr_foreign_toplevel_handle_v1_fullscreen_event*)data;
g_pCompositor->setWindowFullscreen(this, EV->fullscreen, FULLSCREEN_FULL);
}, this, "Toplevel");
hyprListener_toplevelClose.initCallback(&m_phForeignToplevel->events.request_close, [&](void* owner, void* data) {
g_pCompositor->closeWindow(this);
}, this, "Toplevel");
m_iLastToplevelMonitorID = m_iMonitorID;
}
void CWindow::destroyToplevelHandle() {
if (!m_phForeignToplevel)
return;
hyprListener_toplevelActivate.removeCallback();
hyprListener_toplevelClose.removeCallback();
hyprListener_toplevelFullscreen.removeCallback();
wlr_foreign_toplevel_handle_v1_destroy(m_phForeignToplevel);
m_phForeignToplevel = nullptr;
}
void CWindow::updateToplevel() {
updateSurfaceOutputs();
if (!m_phForeignToplevel)
return;
wlr_foreign_toplevel_handle_v1_set_title(m_phForeignToplevel, m_szTitle.c_str());
wlr_foreign_toplevel_handle_v1_set_fullscreen(m_phForeignToplevel, m_bIsFullscreen);
if (m_iLastToplevelMonitorID != m_iMonitorID) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iLastToplevelMonitorID); PMONITOR && PMONITOR->m_bEnabled)
wlr_foreign_toplevel_handle_v1_output_leave(m_phForeignToplevel, PMONITOR->output);
wlr_foreign_toplevel_handle_v1_output_enter(m_phForeignToplevel, g_pCompositor->getMonitorFromID(m_iMonitorID)->output);
m_iLastToplevelMonitorID = m_iMonitorID;
}
}
void sendEnterIter(wlr_surface* pSurface, int x, int y, void* data) {
const auto OUTPUT = (wlr_output*)data;
wlr_surface_send_enter(pSurface, OUTPUT);
}
void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
const auto OUTPUT = (wlr_output*)data;
wlr_surface_send_leave(pSurface, OUTPUT);
}
void CWindow::updateSurfaceOutputs() {
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden || !m_bMappedX11)
return;
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
m_iLastSurfaceMonitorID = m_iMonitorID;
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(this), sendLeaveIter, PLASTMONITOR->output);
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(this), sendEnterIter, PNEWMONITOR->output);
}
void CWindow::moveToWorkspace(int workspaceID) {
if (m_iWorkspaceID != workspaceID) {
m_iWorkspaceID = workspaceID;
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); PWORKSPACE) {
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%x,%s", this, PWORKSPACE->m_szName.c_str())});
}
}
}
CWindow* CWindow::X11TransientFor() {
if (!m_bIsX11)
return nullptr;
if (!m_uSurface.xwayland->parent)
return nullptr;
auto PPARENT = g_pCompositor->getWindowFromSurface(m_uSurface.xwayland->parent->surface);
while (g_pCompositor->windowValidMapped(PPARENT) && PPARENT->m_uSurface.xwayland->parent) {
PPARENT = g_pCompositor->getWindowFromSurface(PPARENT->m_uSurface.xwayland->parent->surface);
}
if (!g_pCompositor->windowValidMapped(PPARENT))
return nullptr;
return PPARENT;
}
void CWindow::removeDecorationByType(eDecorationType type) {
for (auto& wd : m_dWindowDecorations) {
if (wd->getDecorationType() == type)
m_vDecosToRemove.push_back(wd.get());
}
updateWindowDecos();
}
void CWindow::onUnmap() {
if (g_pCompositor->m_pLastWindow == this)
g_pCompositor->m_pLastWindow = nullptr;
}
void CWindow::setHidden(bool hidden) {
m_bHidden = hidden;
if (hidden) {
onUnmap();
}
}
bool CWindow::isHidden() {
return m_bHidden;
} }

View File

@@ -13,13 +13,20 @@ struct SWindowSpecialRenderData {
// set by the layout // set by the layout
bool rounding = true; bool rounding = true;
}; bool border = true;
bool decorate = true;
};
struct SWindowAdditionalConfigData { struct SWindowAdditionalConfigData {
std::string animationStyle = ""; std::string animationStyle = "";
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 forceAllowsInput = false;
bool forceNoAnims = false;
bool forceNoBorder = false;
bool forceNoShadow = false;
bool windowDanceCompat = false;
}; };
class CWindow { class CWindow {
@@ -39,6 +46,11 @@ public:
DYNLISTENER(requestMinimize); DYNLISTENER(requestMinimize);
DYNLISTENER(requestMaximize); DYNLISTENER(requestMaximize);
DYNLISTENER(requestResize); DYNLISTENER(requestResize);
DYNLISTENER(activateX11);
DYNLISTENER(configureX11);
DYNLISTENER(toplevelClose);
DYNLISTENER(toplevelActivate);
DYNLISTENER(toplevelFullscreen);
// DYNLISTENER(newSubsurfaceWindow); // DYNLISTENER(newSubsurfaceWindow);
union { union {
@@ -58,6 +70,9 @@ public:
Vector2D m_vReportedPosition; Vector2D m_vReportedPosition;
Vector2D m_vReportedSize; Vector2D m_vReportedSize;
// for restoring floating statuses
Vector2D m_vLastFloatingSize;
// this is used for pseudotiling // this is used for pseudotiling
bool m_bIsPseudotiled = false; bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(0,0); Vector2D m_vPseudoSize = Vector2D(0,0);
@@ -84,14 +99,16 @@ public:
uint64_t m_iX11Type = 0; uint64_t m_iX11Type = 0;
bool m_bIsModal = false; bool m_bIsModal = false;
bool m_bX11DoesntWantBorders = false; bool m_bX11DoesntWantBorders = false;
DYNLISTENER(activateX11); bool m_bX11ShouldntFocus = false;
DYNLISTENER(configureX11);
// //
// For nofocus // For nofocus
bool m_bNoFocus = false; bool m_bNoFocus = false;
bool m_bNoInitialFocus = false; bool m_bNoInitialFocus = false;
// initial fullscreen
bool m_bWantsInitialFullscreen = false;
SSurfaceTreeNode* m_pSurfaceTree = nullptr; SSurfaceTreeNode* m_pSurfaceTree = nullptr;
// Animated border // Animated border
@@ -104,8 +121,11 @@ 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 // For pinned (sticky) windows
bool m_bHidden = false; bool m_bPinned = false;
// for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window.
CWindow* m_pLastCycledWindow = nullptr;
// Foreign Toplevel proto // Foreign Toplevel proto
wlr_foreign_toplevel_handle_v1* m_phForeignToplevel = nullptr; wlr_foreign_toplevel_handle_v1* m_phForeignToplevel = nullptr;
@@ -124,6 +144,16 @@ public:
// animated shadow color // animated shadow color
CAnimatedVariable m_cRealShadowColor; CAnimatedVariable m_cRealShadowColor;
// animated tint
CAnimatedVariable m_fDimPercent;
// swallowing
CWindow* m_pSwallowed = nullptr;
// for toplevel monitor events
uint64_t m_iLastToplevelMonitorID = -1;
uint64_t m_iLastSurfaceMonitorID = -1;
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) { bool operator==(const CWindow& rhs) {
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut; return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut;
@@ -135,5 +165,19 @@ public:
void updateWindowDecos(); void updateWindowDecos();
pid_t getPID(); pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType); IHyprWindowDecoration* getDecorationByType(eDecorationType);
void removeDecorationByType(eDecorationType);
void createToplevelHandle();
void destroyToplevelHandle();
void updateToplevel();
void updateSurfaceOutputs();
void moveToWorkspace(int);
CWindow* X11TransientFor();
void onUnmap();
void setHidden(bool hidden);
bool isHidden();
private:
// For hidden windows and stuff
bool m_bHidden = false;
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -20,9 +20,10 @@
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]} #define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
struct SConfigValue { struct SConfigValue {
int64_t intValue = -1; int64_t intValue = -INT64_MAX;
float floatValue = -1; float floatValue = -__FLT_MAX__;
std::string strValue = ""; std::string strValue = "";
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
bool set = false; // used for device configs bool set = false; // used for device configs
}; };
@@ -36,6 +37,8 @@ struct SMonitorRule {
std::string defaultWorkspace = ""; std::string defaultWorkspace = "";
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 = "";
bool enable10bit = false;
}; };
struct SMonitorAdditionalReservedArea { struct SMonitorAdditionalReservedArea {
@@ -48,6 +51,12 @@ struct SMonitorAdditionalReservedArea {
struct SWindowRule { struct SWindowRule {
std::string szRule; std::string szRule;
std::string szValue; 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 {
@@ -62,6 +71,48 @@ struct SAnimationPropertyConfig {
SAnimationPropertyConfig* pParentAnimation = nullptr; SAnimationPropertyConfig* pParentAnimation = nullptr;
}; };
class CVarList {
public:
CVarList(const std::string& in, long unsigned int lastArgNo = 0) {
std::string curitem = "";
std::string argZ = in;
auto nextItem = [&]() {
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : argZ.find_first_of(',');
if (idx != std::string::npos) {
curitem = argZ.substr(0, idx);
argZ = argZ.substr(idx + 1);
} else {
curitem = argZ;
argZ = STRVAL_EMPTY;
}
};
nextItem();
while (curitem != STRVAL_EMPTY) {
m_vArgs.push_back(removeBeginEndSpacesTabs(curitem));
nextItem();
}
};
~CVarList() = default;
int size() const {
return m_vArgs.size();
}
std::string operator[](const long unsigned int& idx) const {
if (idx >= m_vArgs.size())
return "";
return m_vArgs[idx];
}
private:
std::vector<std::string> m_vArgs;
};
class CConfigManager { class CConfigManager {
public: public:
CConfigManager(); CConfigManager();
@@ -83,8 +134,11 @@ public:
bool shouldBlurLS(const std::string&); bool shouldBlurLS(const std::string&);
SConfigValue* getConfigValuePtr(std::string); SConfigValue* getConfigValuePtr(std::string);
SConfigValue* getConfigValuePtrSafe(std::string);
SMonitorRule getMonitorRuleFor(std::string); SMonitorRule getMonitorRuleFor(std::string, std::string displayName = "");
CMonitor* getBoundMonitorForWS(std::string);
std::vector<SWindowRule> getMatchingRules(CWindow*); std::vector<SWindowRule> getMatchingRules(CWindow*);
@@ -96,11 +150,18 @@ public:
void performMonitorReload(); void performMonitorReload();
bool m_bWantsMonitorReload = false; bool m_bWantsMonitorReload = false;
bool m_bForceReload = false; bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
void ensureDPMS();
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);
void addParseError(const std::string&);
SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&); SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&);
std::string configCurrentPath;
private: private:
std::deque<std::string> configPaths; // stores all the config paths std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
@@ -110,14 +171,14 @@ private:
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
std::string configCurrentPath;
std::string currentCategory = ""; // For storing the category of the current item std::string currentCategory = ""; // For storing the category of the current item
std::string parseError = ""; // For storing a parse error to display later std::string parseError = ""; // For storing a parse error to display later
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
std::vector<std::pair<std::string, std::string>> boundWorkspaces;
bool isFirstLaunch = true; // For exec-once bool isFirstLaunch = true; // For exec-once
std::deque<SMonitorRule> m_dMonitorRules; std::deque<SMonitorRule> m_dMonitorRules;
@@ -131,7 +192,6 @@ private:
void setDefaultVars(); void setDefaultVars();
void setDefaultAnimationVars(); void setDefaultAnimationVars();
void setDeviceDefaultVars(const std::string&); void setDeviceDefaultVars(const std::string&);
void ensureDPMS();
void setAnimForChildren(SAnimationPropertyConfig *const); void setAnimForChildren(SAnimationPropertyConfig *const);
@@ -147,12 +207,14 @@ private:
void handleBind(const std::string&, const std::string&); void handleBind(const std::string&, const std::string&);
void handleUnbind(const std::string&, const std::string&); void handleUnbind(const std::string&, const std::string&);
void handleWindowRule(const std::string&, const std::string&); void handleWindowRule(const std::string&, const std::string&);
void handleWindowRuleV2(const std::string&, const std::string&);
void handleDefaultWorkspace(const std::string&, const std::string&); void handleDefaultWorkspace(const std::string&, const std::string&);
void handleBezier(const std::string&, const std::string&); void handleBezier(const std::string&, const std::string&);
void handleAnimation(const std::string&, const std::string&); void handleAnimation(const std::string&, const std::string&);
void handleSource(const std::string&, const std::string&); void handleSource(const std::string&, const std::string&);
void handleSubmap(const std::string&, const std::string&); void handleSubmap(const std::string&, const std::string&);
void handleBlurLS(const std::string&, const std::string&); void handleBlurLS(const std::string&, const std::string&);
void handleBindWS(const std::string&, const std::string&);
}; };
inline std::unique_ptr<CConfigManager> g_pConfigManager; inline std::unique_ptr<CConfigManager> g_pConfigManager;

View File

@@ -9,117 +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
monitor=,preferred,0x0,1 # See https://wiki.hyprland.org/Configuring/Monitors/
monitor=,preferred,auto,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_layout= kb_layout = us
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.
} }
general { general {
sensitivity=1.0 # for mouse cursor # See https://wiki.hyprland.org/Configuring/Variables/ for more
main_mod=SUPER
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(1affffee)
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, more passes = more resource intensive. blur = yes
# Your blur "amount" is blur_size * blur_passes, but high blur_size (over around 5-ish) will produce artifacts. blur_size = 3
# if you want heavy blur, you need to up the blur_passes. blur_passes = 1
# the more passes, the more you can up the blur_size without noticing artifacts. 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
# example binds # Example windowrule v1
bind=SUPER,Q,exec,kitty # windowrule = float, ^(kitty)$
bind=SUPER,RETURN,exec,alacritty # Example windowrule v2
bind=SUPER,C,killactive, # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
bind=SUPER,M,exit, # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
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
bind=SUPER,right,movefocus,r
bind=SUPER,up,movefocus,u
bind=SUPER,down,movefocus,d
bind=SUPER,1,workspace,1 # See https://wiki.hyprland.org/Configuring/Keywords/ for more
bind=SUPER,2,workspace,2 $mainMod = SUPER
bind=SUPER,3,workspace,3
bind=SUPER,4,workspace,4
bind=SUPER,5,workspace,5
bind=SUPER,6,workspace,6
bind=SUPER,7,workspace,7
bind=SUPER,8,workspace,8
bind=SUPER,9,workspace,9
bind=SUPER,0,workspace,10
bind=ALT,1,movetoworkspace,1 # Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind=ALT,2,movetoworkspace,2 bind = $mainMod, Q, exec, kitty
bind=ALT,3,movetoworkspace,3 bind = $mainMod, C, killactive,
bind=ALT,4,movetoworkspace,4 bind = $mainMod, M, exit,
bind=ALT,5,movetoworkspace,5 bind = $mainMod, E, exec, dolphin
bind=ALT,6,movetoworkspace,6 bind = $mainMod, V, togglefloating,
bind=ALT,7,movetoworkspace,7 bind = $mainMod, R, exec, wofi --show drun
bind=ALT,8,movetoworkspace,8 bind = $mainMod, P, pseudo, # dwindle
bind=ALT,9,movetoworkspace,9 bind = $mainMod, J, togglesplit, # dwindle
bind=ALT,0,movetoworkspace,10
bind=SUPER,mouse_down,workspace,e+1 # Move focus with mainMod + arrow keys
bind=SUPER,mouse_up,workspace,e-1 bind = $mainMod, left, movefocus, l
)#"; bind = $mainMod, right, movefocus, r
bind = $mainMod, up, movefocus, u
bind = $mainMod, down, movefocus, d
# Switch workspaces with mainMod + [0-9]
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

@@ -17,12 +17,13 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = ""; std::string result = "";
if (format == HyprCtl::FORMAT_JSON) { if (format == HyprCtl::FORMAT_JSON) {
result += "["; result += "[";
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
result += getFormat( result += getFormat(
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,
"active": "%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 ? "yes" : "no") (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false")
); );
} }
@@ -56,8 +60,8 @@ R"#({
result += "]"; result += "]";
} else { } else {
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tactive workspace: %i (%s)\n\treserved: %i %i %i %i\n\tscale: %.2f\n\ttransform: %i\n\tactive: %s\n\n", result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\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);
} }
} }
@@ -80,37 +84,44 @@ R"#({
"id": %i, "id": %i,
"name": "%s" "name": "%s"
}, },
"floating": %i, "floating": %s,
"monitor": %i, "monitor": %i,
"class": "%s", "class": "%s",
"title": "%s", "title": "%s",
"pid": %i, "pid": %i,
"xwayland": %i "xwayland": %s,
"pinned": %s,
"fullscreen": %s,
"fullscreenMode": %i
},)#", },)#",
w.get(), w.get(),
(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, ((int)w->m_bIsFloating == 1 ? "true" : "false"),
w->m_iMonitorID, w->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(), escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w.get())).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(), escapeJSONStrings(g_pXWaylandManager->getTitle(w.get())).c_str(),
w->getPID(), w->getPID(),
(int)w->m_bIsX11 ((int)w->m_bIsX11 == 1 ? "true" : "false"),
(w->m_bPinned ? "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)
); );
} }
} }
// remove trailing comma // remove trailing comma
result.pop_back(); if (result != "[")
result.pop_back();
result += "]"; result += "]";
} 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\n", 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",
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); w.get(), 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.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));
} }
} }
} }
@@ -123,19 +134,25 @@ std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
result += "["; result += "[";
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
const auto PLASTW = w->getLastFocusedWindow();
result += getFormat( result += getFormat(
R"#({ R"#({
"id": %i, "id": %i,
"name": "%s", "name": "%s",
"monitor": "%s", "monitor": "%s",
"windows": %i, "windows": %i,
"hasfullscreen": %i "hasfullscreen": %s,
"lastwindow": "0x%x",
"lastwindowtitle": "%s"
},)#", },)#",
w->m_iID, w->m_iID,
escapeJSONStrings(w->m_szName).c_str(), escapeJSONStrings(w->m_szName).c_str(),
escapeJSONStrings(g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName).c_str(), escapeJSONStrings(g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName).c_str(),
g_pCompositor->getWindowsOnWorkspace(w->m_iID), g_pCompositor->getWindowsOnWorkspace(w->m_iID),
(int)w->m_bHasFullscreenWindow ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"),
PLASTW,
PLASTW ? escapeJSONStrings(PLASTW->m_szTitle).c_str() : ""
); );
} }
@@ -145,8 +162,9 @@ R"#({
result += "]"; result += "]";
} else { } else {
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getFormat("workspace ID %i (%s) on monitor %s:\n\twindows: %i\n\thasfullscreen: %i\n\n", const auto PLASTW = w->getLastFocusedWindow();
w->m_iID, w->m_szName.c_str(), g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow); result += getFormat("workspace ID %i (%s) on monitor %s:\n\twindows: %i\n\thasfullscreen: %i\n\tlastwindow: 0x%x\n\tlastwindowtitle: %s\n\n",
w->m_iID, w->m_szName.c_str(), g_pCompositor->getMonitorFromID(w->m_iMonitorID)->szName.c_str(), g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow, PLASTW, PLASTW ? PLASTW->m_szTitle.c_str() : "");
} }
} }
return result; return result;
@@ -156,7 +174,7 @@ std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!g_pCompositor->windowValidMapped(PWINDOW))
return "Invalid"; return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid";
if (format == HyprCtl::FORMAT_JSON) { if (format == HyprCtl::FORMAT_JSON) {
return getFormat( return getFormat(
@@ -168,23 +186,23 @@ R"#({
"id": %i, "id": %i,
"name": "%s" "name": "%s"
}, },
"floating": %i, "floating": %s,
"monitor": %i, "monitor": %i,
"class": "%s", "class": "%s",
"title": "%s", "title": "%s",
"pid": %i, "pid": %i,
"xwayland": %i "xwayland": %s
})#", })#",
PWINDOW, PWINDOW,
(int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y,
(int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y,
PWINDOW->m_iWorkspaceID, escapeJSONStrings(PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName).c_str(), PWINDOW->m_iWorkspaceID, escapeJSONStrings(PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName).c_str(),
(int)PWINDOW->m_bIsFloating, ((int)PWINDOW->m_bIsFloating == 1 ? "true" : "false"),
PWINDOW->m_iMonitorID, PWINDOW->m_iMonitorID,
escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(), escapeJSONStrings(g_pXWaylandManager->getAppIDClass(PWINDOW)).c_str(),
escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(), escapeJSONStrings(g_pXWaylandManager->getTitle(PWINDOW)).c_str(),
PWINDOW->getPID(), PWINDOW->getPID(),
(int)PWINDOW->m_bIsX11 ((int)PWINDOW->m_bIsX11 == 1 ? "true" : "false")
); );
} else { } else {
return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\n", return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: %i\n\txwayland: %i\n\n",
@@ -204,12 +222,12 @@ R"#("%s": {
"levels": { "levels": {
)#", )#",
escapeJSONStrings(mon->szName).c_str() escapeJSONStrings(mon->szName).c_str()
); );
int layerLevel = 0; int layerLevel = 0;
for (auto& level : mon->m_aLayerSurfaceLists) { for (auto& level : mon->m_aLayerSurfaceLists) {
result += getFormat( result += getFormat(
R"#( R"#(
"%i": [ "%i": [
)#", )#",
layerLevel layerLevel
@@ -254,7 +272,7 @@ R"#( {
result.pop_back(); result.pop_back();
result += "\n}\n"; result += "\n}\n";
} else { } else {
for (auto& mon : g_pCompositor->m_vMonitors) { for (auto& mon : g_pCompositor->m_vMonitors) {
result += getFormat("Monitor %s:\n", mon->szName.c_str()); result += getFormat("Monitor %s:\n", mon->szName.c_str());
@@ -286,10 +304,12 @@ std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
result += getFormat( result += getFormat(
R"#( { R"#( {
"address": "0x%x", "address": "0x%x",
"name": "%s" "name": "%s",
"defaultSpeed": %f
},)#", },)#",
&m, &m,
escapeJSONStrings(m.mouse->name).c_str() escapeJSONStrings(m.mouse->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
); );
} }
@@ -299,7 +319,7 @@ R"#( {
result += "\"keyboards\": [\n"; result += "\"keyboards\": [\n";
for (auto& k : g_pInputManager->m_lKeyboards) { for (auto& k : g_pInputManager->m_lKeyboards) {
const auto KM = xkb_keymap_layout_get_name(wlr_keyboard_from_input_device(k.keyboard)->keymap, 0); const auto KM = g_pInputManager->getActiveLayoutForKeyboard(&k);
result += getFormat( result += getFormat(
R"#( { R"#( {
"address": "0x%x", "address": "0x%x",
@@ -309,7 +329,8 @@ R"#( {
"layout": "%s", "layout": "%s",
"variant": "%s", "variant": "%s",
"options": "%s", "options": "%s",
"active_keymap": "%s" "active_keymap": "%s",
"main": %s
},)#", },)#",
&k, &k,
escapeJSONStrings(k.keyboard->name).c_str(), escapeJSONStrings(k.keyboard->name).c_str(),
@@ -318,7 +339,8 @@ R"#( {
escapeJSONStrings(k.currentRules.layout).c_str(), escapeJSONStrings(k.currentRules.layout).c_str(),
escapeJSONStrings(k.currentRules.variant).c_str(), escapeJSONStrings(k.currentRules.variant).c_str(),
escapeJSONStrings(k.currentRules.options).c_str(), escapeJSONStrings(k.currentRules.options).c_str(),
escapeJSONStrings(KM).c_str() escapeJSONStrings(KM).c_str(),
(k.active ? "true" : "false")
); );
} }
@@ -367,6 +389,41 @@ R"#( {
); );
} }
// remove trailing comma
result.pop_back();
result += "\n],\n";
result += "\"touch\": [\n";
for (auto& d : g_pInputManager->m_lTouchDevices) {
result += getFormat(
R"#( {
"address": "0x%x",
"name": "%s"
},)#",
&d,
d.pWlrDevice ? d.pWlrDevice->name : ""
);
}
// 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"#( {
"address": "0x%x",
"name": "%s"
},)#",
&d,
d.pWlrDevice ? d.pWlrDevice->name : ""
);
}
// remove trailing comma // remove trailing comma
if (result[result.size() - 1] == ',') if (result[result.size() - 1] == ',')
result.pop_back(); result.pop_back();
@@ -378,14 +435,14 @@ 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", &m, m.mouse->name); 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 += "\n\nKeyboards:\n"; result += "\n\nKeyboards:\n";
for (auto& k : g_pInputManager->m_lKeyboards) { for (auto& k : g_pInputManager->m_lKeyboards) {
const auto KM = xkb_keymap_layout_get_name(wlr_keyboard_from_input_device(k.keyboard)->keymap, 0); const auto KM = g_pInputManager->getActiveLayoutForKeyboard(&k);
result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n", &k, k.keyboard->name, k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM); result += getFormat("\tKeyboard at %x:\n\t\t%s\n\t\t\trules: r \"%s\", m \"%s\", l \"%s\", v \"%s\", o \"%s\"\n\t\t\tactive keymap: %s\n\t\t\tmain: %s\n", &k, k.keyboard->name, k.currentRules.rules.c_str(), k.currentRules.model.c_str(), k.currentRules.layout.c_str(), k.currentRules.variant.c_str(), k.currentRules.options.c_str(), KM.c_str(), (k.active ? "yes" : "no"));
} }
result += "\n\nTablets:\n"; result += "\n\nTablets:\n";
@@ -401,28 +458,73 @@ R"#( {
for (auto& d : g_pInputManager->m_lTabletTools) { for (auto& d : g_pInputManager->m_lTabletTools) {
result += getFormat("\tTablet Tool at %x (belongs to %x)\n", &d, d.wlrTabletTool ? d.wlrTabletTool->data : 0); result += getFormat("\tTablet Tool at %x (belongs to %x)\n", &d, d.wlrTabletTool ? d.wlrTabletTool->data : 0);
} }
result += "\n\nTouch:\n";
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 += "\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 : "");
}
} }
return result; return result;
} }
std::string versionRequest() { std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + GIT_DIRTY + " (" + GIT_COMMIT_MESSAGE + ").\nflags: (if any)\n";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + GIT_DIRTY + " (" + removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE).c_str() + ").\nflags: (if any)\n";
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "legacyrenderer\n"; result += "legacyrenderer\n";
#endif #endif
#ifndef NDEBUG #ifndef NDEBUG
result += "debug\n"; result += "debug\n";
#endif #endif
#ifdef HYPRLAND_DEBUG #ifdef HYPRLAND_DEBUG
result += "debug\n"; result += "debug\n";
#endif #endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
result += "no xwayland\n"; result += "no xwayland\n";
#endif #endif
return result; return result;
} else {
std::string result = getFormat(
R"#({
"branch": "%s",
"commit": "%s",
"dirty": %s,
"commit_message": "%s",
"flags": [)#", GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE).c_str());
#ifdef LEGACY_RENDERER
result += "\"legacyrenderer\",";
#endif
#ifndef NDEBUG
result += "\"debug\",";
#endif
#ifdef HYPRLAND_DEBUG
result += "\"debug\",";
#endif
#ifdef NO_XWAYLAND
result += "\"no xwayland\",";
#endif
if (result[result.length() - 1] == ',')
result.pop_back();
result += "]\n}";
return result;
}
return ""; // make the compiler happy
} }
std::string dispatchRequest(std::string in) { std::string dispatchRequest(std::string in) {
@@ -457,23 +559,35 @@ std::string dispatchKeyword(std::string in) {
if (COMMAND == "monitor") if (COMMAND == "monitor")
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords
if (COMMAND.contains("input")) if (COMMAND.contains("input") || COMMAND.contains("device:")) {
g_pInputManager->setKeyboardLayout(); // update kb layout g_pInputManager->setKeyboardLayout(); // update kb layout
g_pInputManager->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
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 == "")
return "ok"; return "ok";
return retval; return retval;
} }
std::string reloadRequest() { std::string reloadRequest(std::string request) {
const auto REQMODE = request.substr(request.find_last_of(' ') + 1);
g_pConfigManager->m_bForceReload = true; g_pConfigManager->m_bForceReload = true;
if (REQMODE == "config-only") {
g_pConfigManager->m_bNoMonitorReload = true;
}
g_pConfigManager->tick();
return "ok"; return "ok";
} }
@@ -487,6 +601,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) {
@@ -521,6 +652,97 @@ std::string dispatchBatch(std::string request) {
return reply; return reply;
} }
std::string dispatchSetCursor(std::string request) {
std::string curitem = "";
auto nextItem = [&]() {
auto idx = request.find_first_of(' ');
if (idx != std::string::npos) {
curitem = request.substr(0, idx);
request = request.substr(idx + 1);
} else {
curitem = request;
request = "";
}
curitem = removeBeginEndSpacesTabs(curitem);
};
nextItem();
nextItem();
const auto THEME = curitem;
nextItem();
const auto SIZE = curitem;
if (!isNumber(SIZE)) {
return "size not int";
}
const auto SIZEINT = std::stoi(SIZE);
if (SIZEINT < 1) {
return "size must be positive";
}
wlr_xcursor_manager_destroy(g_pCompositor->m_sWLRXCursorMgr);
g_pCompositor->m_sWLRXCursorMgr = wlr_xcursor_manager_create(THEME.c_str(), SIZEINT);
setenv("XCURSOR_SIZE", SIZE.c_str(), true);
setenv("XCURSOR_THEME", THEME.c_str(), true);
for (auto& m : g_pCompositor->m_vMonitors) {
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, m->scale);
}
return "ok";
}
std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
std::string curitem = "";
auto nextItem = [&]() {
auto idx = request.find_first_of(' ');
if (idx != std::string::npos) {
curitem = request.substr(0, idx);
request = request.substr(idx + 1);
} else {
curitem = request;
request = "";
}
curitem = removeBeginEndSpacesTabs(curitem);
};
nextItem();
nextItem();
const auto PCFGOPT = g_pConfigManager->getConfigValuePtrSafe(curitem);
if (!PCFGOPT)
return "no such option";
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL)
return getFormat("option %s\n\tint: %i\n\tfloat: %f\n\tstr: \"%s\"", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str());
else {
return getFormat(
R"#(
{
"option": "%s",
"int": %i,
"float": %f,
"str": "%s"
}
)#", curitem.c_str(), PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue.c_str()
);
}
}
std::string getReply(std::string request) { std::string getReply(std::string request) {
auto format = HyprCtl::FORMAT_NORMAL; auto format = HyprCtl::FORMAT_NORMAL;
@@ -533,7 +755,7 @@ std::string getReply(std::string request) {
} }
sepIndex++; sepIndex++;
if (c == 'j') if (c == 'j')
format = HyprCtl::FORMAT_JSON; format = HyprCtl::FORMAT_JSON;
} }
@@ -555,26 +777,44 @@ std::string getReply(std::string request) {
else if (request == "layers") else if (request == "layers")
return layersRequest(format); return layersRequest(format);
else if (request == "version") else if (request == "version")
return versionRequest(); return versionRequest(format);
else if (request == "reload") else if (request.find("reload") == 0)
return reloadRequest(); return reloadRequest(request);
else if (request == "devices") else if (request == "devices")
return devicesRequest(format); return devicesRequest(format);
else if (request == "splash") else if (request == "splash")
return splashRequest(); return splashRequest();
else if (request == "cursorpos")
return cursorPosRequest(format);
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)
return dispatchKeyword(request); return dispatchKeyword(request);
else if (request.find("setcursor") == 0)
return dispatchSetCursor(request);
else if (request.find("getoption") == 0)
return dispatchGetOption(request, format);
else if (request.find("[[BATCH]]") == 0) else if (request.find("[[BATCH]]") == 0)
return dispatchBatch(request); return dispatchBatch(request);
return "unknown request"; return "unknown request";
} }
void HyprCtl::tickHyprCtl() { int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
if (!requestMade) if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
return; return 0;
sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress);
const auto ACCEPTEDCONNECTION = accept(HyprCtl::iSocketFD, (sockaddr*)&clientAddress, &clientSize);
char readBuffer[1024];
auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024);
readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0';
std::string request(readBuffer);
std::string reply = ""; std::string reply = "";
@@ -585,82 +825,38 @@ void HyprCtl::tickHyprCtl() {
reply = "Err: " + std::string(e.what()); reply = "Err: " + std::string(e.what());
} }
request = reply; write(ACCEPTEDCONNECTION, reply.c_str(), reply.length());
requestMade = false; close(ACCEPTEDCONNECTION);
requestReady = true;
}
std::string getRequestFromThread(std::string rq) { if (g_pConfigManager->m_bWantsMonitorReload) {
g_pConfigManager->ensureDPMS();
while (HyprCtl::request != "" || HyprCtl::requestMade || HyprCtl::requestReady) {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
} }
HyprCtl::request = rq; return 0;
HyprCtl::requestMade = true;
while (!HyprCtl::requestReady) {
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
HyprCtl::requestReady = false;
HyprCtl::requestMade = false;
std::string toReturn = HyprCtl::request;
HyprCtl::request = "";
return toReturn;
} }
void HyprCtl::startHyprCtlSocket() { void HyprCtl::startHyprCtlSocket() {
std::thread([&]() {
const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
if (SOCKET < 0) { iSocketFD = socket(AF_UNIX, SOCK_STREAM, 0);
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
return;
}
sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; if (iSocketFD < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
return;
}
std::string socketPath = "/tmp/hypr/" + g_pCompositor->m_szInstanceSignature + "/.socket.sock"; sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX};
strcpy(SERVERADDRESS.sun_path, socketPath.c_str()); std::string socketPath = "/tmp/hypr/" + g_pCompositor->m_szInstanceSignature + "/.socket.sock";
bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)); strcpy(SERVERADDRESS.sun_path, socketPath.c_str());
// 10 max queued. bind(iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS));
listen(SOCKET, 10);
sockaddr_in clientAddress; // 10 max queued.
socklen_t clientSize = sizeof(clientAddress); listen(iSocketFD, 10);
char readBuffer[1024] = {0}; Debug::log(LOG, "Hypr socket started at %s", socketPath.c_str());
Debug::log(LOG, "Hypr socket started at %s", socketPath.c_str()); wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
}
while(1) {
const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize);
if (ACCEPTEDCONNECTION < 0) {
Debug::log(ERR, "Couldn't listen on the Hyprland Socket. (3) IPC will not work.");
break;
}
auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024);
readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0';
std::string request(readBuffer);
std::string reply = getRequestFromThread(request);
write(ACCEPTEDCONNECTION, reply.c_str(), reply.length());
close(ACCEPTEDCONNECTION);
}
close(SOCKET);
}).detach();
}

View File

@@ -6,7 +6,6 @@
namespace HyprCtl { namespace HyprCtl {
void startHyprCtlSocket(); void startHyprCtlSocket();
void tickHyprCtl();
// very simple thread-safe request method // very simple thread-safe request method
inline bool requestMade = false; inline bool requestMade = false;
@@ -15,6 +14,10 @@ namespace HyprCtl {
inline std::ifstream requestStream; inline std::ifstream requestStream;
inline wl_event_source* hyprCtlTickSource = nullptr;
inline int iSocketFD = -1;
enum eHyprCtlOutputFormat { enum eHyprCtlOutputFormat {
FORMAT_NORMAL = 0, FORMAT_NORMAL = 0,
FORMAT_JSON FORMAT_JSON

View File

@@ -6,10 +6,23 @@
#include <iostream> #include <iostream>
void Debug::init(std::string IS) { void Debug::init(std::string IS) {
if (ISDEBUG) logFile = "/tmp/hypr/" + IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
logFile = "/tmp/hypr/" + IS + "/hyprlandd.log"; }
else
logFile = "/tmp/hypr/" + IS + "/hyprland.log"; void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
char* outputStr = nullptr;
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
vasprintf(&outputStr, fmt, args);
std::string output = std::string(outputStr);
free(outputStr);
ofs << "[wlr] " << output << "\n";
ofs.close();
} }
void Debug::log(LogLevel level, const char* fmt, ...) { void Debug::log(LogLevel level, const char* fmt, ...) {
@@ -45,7 +58,7 @@ void Debug::log(LogLevel level, const char* fmt, ...) {
if (disableTime && !*disableTime) { if (disableTime && !*disableTime) {
auto timet = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); auto timet = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
const auto MILLIS = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() % 1000; const auto MILLIS = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() % 1000;
ofs << std::put_time(std::localtime(&timet), "[%H:%M:%S:"); ofs << std::put_time(std::localtime(&timet), "[%H:%M:%S:");
if (MILLIS > 99) if (MILLIS > 99)

View File

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

View File

@@ -28,7 +28,7 @@
#define PIXMAN_DAMAGE_FOREACH(region) int rectsNum = 0; \ #define PIXMAN_DAMAGE_FOREACH(region) int rectsNum = 0; \
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 interface class #define interface class
@@ -74,4 +74,4 @@
#define GIT_DIRTY "?" #define GIT_DIRTY "?"
#endif #endif
#define SPECIAL_WORKSPACE_ID -99 #define SPECIAL_WORKSPACE_ID -99

View File

@@ -72,8 +72,7 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
break; break;
case WLR_INPUT_DEVICE_TOUCH: case WLR_INPUT_DEVICE_TOUCH:
Debug::log(LOG, "Attached a touch device with name %s", DEVICE->name); Debug::log(LOG, "Attached a touch device with name %s", DEVICE->name);
Debug::log(WARN, "!!!! Hyprland does not directly support touchscreens, bugs may occur !!!!"); g_pInputManager->newTouchDevice(DEVICE);
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, DEVICE);
break; break;
case WLR_INPUT_DEVICE_TABLET_TOOL: case WLR_INPUT_DEVICE_TABLET_TOOL:
Debug::log(LOG, "Attached a tablet tool with name %s", DEVICE->name); Debug::log(LOG, "Attached a tablet tool with name %s", DEVICE->name);
@@ -83,6 +82,10 @@ 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;
@@ -189,4 +192,34 @@ void Events::listener_pinchUpdate(wl_listener* listener, void* data) {
void Events::listener_pinchEnd(wl_listener* listener, void* data) { void Events::listener_pinchEnd(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_pinch_end_event*)data; const auto EV = (wlr_pointer_pinch_end_event*)data;
wlr_pointer_gestures_v1_send_pinch_end(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, EV->time_msec, EV->cancelled); wlr_pointer_gestures_v1_send_pinch_end(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, EV->time_msec, EV->cancelled);
}
void Events::listener_newVirtualKeyboard(wl_listener* listener, void* data) {
const auto WLRKB = (wlr_virtual_keyboard_v1*)data;
g_pInputManager->newVirtualKeyboard(&WLRKB->keyboard.base);
}
void Events::listener_touchBegin(wl_listener* listener, void* data) {
g_pInputManager->onTouchDown((wlr_touch_down_event*)data);
}
void Events::listener_touchEnd(wl_listener* listener, void* data) {
g_pInputManager->onTouchUp((wlr_touch_up_event*)data);
}
void Events::listener_touchUpdate(wl_listener* listener, void* data) {
g_pInputManager->onTouchMove((wlr_touch_motion_event*)data);
}
void Events::listener_touchFrame(wl_listener* listener, void* data) {
wlr_seat_touch_notify_frame(g_pCompositor->m_sSeat.seat);
}
void Events::listener_holdBegin(wl_listener* listener, void* data) {
g_pInputManager->onPointerHoldBegin((wlr_pointer_hold_begin_event*)data);
}
void Events::listener_holdEnd(wl_listener* listener, void* data) {
g_pInputManager->onPointerHoldEnd((wlr_pointer_hold_end_event*)data);
} }

View File

@@ -12,6 +12,9 @@ namespace Events {
LISTENER(change); LISTENER(change);
LISTENER(newOutput); LISTENER(newOutput);
// DRM events
LISTENER(leaseRequest);
// Layer events // Layer events
LISTENER(newLayerSurface); LISTENER(newLayerSurface);
DYNLISTENFUNC(destroyLayerSurface); DYNLISTENFUNC(destroyLayerSurface);
@@ -39,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);
@@ -64,7 +68,7 @@ namespace Events {
LISTENER(mouseButton); LISTENER(mouseButton);
LISTENER(mouseAxis); LISTENER(mouseAxis);
LISTENER(mouseFrame); LISTENER(mouseFrame);
LISTENER(newInput); LISTENER(newInput);
// Virt Ptr // Virt Ptr
@@ -74,7 +78,7 @@ namespace Events {
DYNLISTENFUNC(keyboardKey); DYNLISTENFUNC(keyboardKey);
DYNLISTENFUNC(keyboardMod); DYNLISTENFUNC(keyboardMod);
DYNLISTENFUNC(keyboardDestroy); DYNLISTENFUNC(keyboardDestroy);
DYNLISTENFUNC(commitConstraint); DYNLISTENFUNC(commitConstraint);
LISTENER(newConstraint); LISTENER(newConstraint);
DYNLISTENFUNC(setConstraintRegion); DYNLISTENFUNC(setConstraintRegion);
@@ -84,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);
@@ -133,4 +136,24 @@ namespace Events {
// Power // Power
LISTENER(powerMgrSetMode); LISTENER(powerMgrSetMode);
};
// IME
LISTENER(newIME);
LISTENER(newTextInput);
LISTENER(newVirtualKeyboard);
// IME Popups
DYNLISTENFUNC(mapInputPopup);
DYNLISTENFUNC(unmapInputPopup);
DYNLISTENFUNC(commitInputPopup);
DYNLISTENFUNC(destroyInputPopup);
// Touch
LISTENER(touchBegin);
LISTENER(touchEnd);
LISTENER(touchUpdate);
LISTENER(touchFrame);
LISTENER(holdBegin);
LISTENER(holdEnd);
};

View File

@@ -133,8 +133,9 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint)) { // don't focus if constrained if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint)) { // don't focus if constrained
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
g_pCompositor->focusSurface(layersurface->layerSurface->surface); g_pCompositor->focusSurface(layersurface->layerSurface->surface);
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
@@ -151,6 +152,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) {
@@ -158,7 +161,9 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
Debug::log(LOG, "LayerSurface %x unmapped", layersurface->layerSurface); Debug::log(LOG, "LayerSurface %x unmapped", layersurface->layerSurface);
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID)) { g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
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.");
g_pCompositor->addToFadingOutSafe(layersurface); g_pCompositor->addToFadingOutSafe(layersurface);
@@ -194,8 +199,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};
@@ -244,7 +270,7 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
if (layersurface->layerSurface->current.committed != 0) { if (layersurface->layerSurface->current.committed != 0) {
if (layersurface->layer != layersurface->layerSurface->current.layer) { if (layersurface->layer != layersurface->layerSurface->current.layer) {
for (auto it = PMONITOR->m_aLayerSurfaceLists[layersurface->layer].begin(); it != PMONITOR->m_aLayerSurfaceLists[layersurface->layer].end(); it++) { for (auto it = PMONITOR->m_aLayerSurfaceLists[layersurface->layer].begin(); it != PMONITOR->m_aLayerSurfaceLists[layersurface->layer].end(); it++) {
if (it->get() == layersurface) { if (it->get() == layersurface) {
PMONITOR->m_aLayerSurfaceLists[layersurface->layerSurface->current.layer].emplace_back(std::move(*it)); PMONITOR->m_aLayerSurfaceLists[layersurface->layerSurface->current.layer].emplace_back(std::move(*it));
@@ -270,4 +296,4 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
layersurface->geometry = {layersurface->geometry.x, layersurface->geometry.y, layersurface->layerSurface->surface->current.width, layersurface->layerSurface->surface->current.height}; layersurface->geometry = {layersurface->geometry.x, layersurface->geometry.y, layersurface->layerSurface->surface->current.width, layersurface->layerSurface->surface->current.height};
g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y); g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y);
} }

View File

@@ -25,6 +25,15 @@ void Events::listener_outputMgrTest(wl_listener* listener, void* data) {
g_pHyprRenderer->outputMgrApplyTest(CONFIG, true); g_pHyprRenderer->outputMgrApplyTest(CONFIG, true);
} }
void Events::listener_leaseRequest(wl_listener* listener, void* data) {
const auto REQUEST = (wlr_drm_lease_request_v1*)data;
struct wlr_drm_lease_v1* lease = wlr_drm_lease_request_v1_grant(REQUEST);
if (!lease) {
Debug::log(ERR, "Failed to grant lease request!");
wlr_drm_lease_request_v1_reject(REQUEST);
}
}
void Events::listener_requestSetPrimarySel(wl_listener* listener, void* data) { void Events::listener_requestSetPrimarySel(wl_listener* listener, void* data) {
const auto EVENT = (wlr_seat_request_set_primary_selection_event*)data; const auto EVENT = (wlr_seat_request_set_primary_selection_event*)data;
wlr_seat_set_primary_selection(g_pCompositor->m_sSeat.seat, EVENT->source, EVENT->serial); wlr_seat_set_primary_selection(g_pCompositor->m_sSeat.seat, EVENT->source, EVENT->serial);
@@ -36,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) {
@@ -63,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) {
@@ -78,7 +89,7 @@ void Events::listener_requestDrag(wl_listener* listener, void* data) {
} }
void Events::listener_startDrag(wl_listener* listener, void* data) { void Events::listener_startDrag(wl_listener* listener, void* data) {
if (g_pInputManager->m_sDrag.drag) if (g_pInputManager->m_sDrag.drag)
return; // don't handle multiple drags return; // don't handle multiple drags
@@ -103,16 +114,31 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
g_pInputManager->m_sDrag.hyprListener_destroyIcon.initCallback(&wlrDrag->icon->events.destroy, &Events::listener_destroyDragIcon, &g_pInputManager->m_sDrag, "DragIcon"); g_pInputManager->m_sDrag.hyprListener_destroyIcon.initCallback(&wlrDrag->icon->events.destroy, &Events::listener_destroyDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
g_pInputManager->m_sDrag.hyprListener_commitIcon.initCallback(&wlrDrag->icon->surface->events.commit, &Events::listener_commitDragIcon, &g_pInputManager->m_sDrag, "DragIcon"); g_pInputManager->m_sDrag.hyprListener_commitIcon.initCallback(&wlrDrag->icon->surface->events.commit, &Events::listener_commitDragIcon, &g_pInputManager->m_sDrag, "DragIcon");
} }
static auto *const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
if (*PFOLLOWONDND)
g_pInputManager->m_pFollowOnDnDBegin = g_pCompositor->m_pLastWindow;
else
g_pInputManager->m_pFollowOnDnDBegin = nullptr;
} }
void Events::listener_destroyDrag(void* owner, void* data) { void Events::listener_destroyDrag(void* owner, void* data) {
Debug::log(LOG, "Drag destroyed."); Debug::log(LOG, "Drag destroyed.");
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_pInputManager->m_sDrag.drag = nullptr; g_pInputManager->m_sDrag.drag = nullptr;
g_pInputManager->m_sDrag.dragIcon = nullptr; g_pInputManager->m_sDrag.dragIcon = nullptr;
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback(); g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
g_pInputManager->refocus(); g_pInputManager->refocus();
if (g_pInputManager->m_pFollowOnDnDBegin)
g_pCompositor->focusWindow(g_pInputManager->m_pFollowOnDnDBegin);
g_pInputManager->m_pFollowOnDnDBegin = nullptr;
} }
void Events::listener_mapDragIcon(void* owner, void* data) { void Events::listener_mapDragIcon(void* owner, void* data) {
@@ -143,7 +169,7 @@ void Events::listener_commitDragIcon(void* owner, void* data) {
void Events::listener_InhibitActivate(wl_listener* listener, void* data) { void Events::listener_InhibitActivate(wl_listener* listener, void* data) {
Debug::log(LOG, "Activated exclusive for %x.", g_pCompositor->m_sSeat.exclusiveClient); Debug::log(LOG, "Activated exclusive for %x.", g_pCompositor->m_sSeat.exclusiveClient);
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pCompositor->m_sSeat.exclusiveClient = g_pCompositor->m_sWLRInhibitMgr->active_client; g_pCompositor->m_sSeat.exclusiveClient = g_pCompositor->m_sWLRInhibitMgr->active_client;
} }
@@ -171,7 +197,19 @@ void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
const auto EVENT = (wlr_output_power_v1_set_mode_event*)data; const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
wlr_output_enable(EVENT->output, EVENT->mode == 1); wlr_output_enable(EVENT->output, EVENT->mode == 1);
if (!wlr_output_commit(EVENT->output)) if (!wlr_output_commit(EVENT->output))
Debug::log(ERR, "Couldn't set power mode"); Debug::log(ERR, "Couldn't set power mode");
} }
void Events::listener_newIME(wl_listener* listener, void* data) {
Debug::log(LOG, "New IME added!");
g_pInputManager->m_sIMERelay.onNewIME((wlr_input_method_v2*)data);
}
void Events::listener_newTextInput(wl_listener* listener, void* data) {
Debug::log(LOG, "New TextInput added!");
g_pInputManager->m_sIMERelay.onNewTextInput((wlr_text_input_v3*)data);
}

View File

@@ -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);
@@ -53,37 +51,53 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
return; return;
} }
if (g_pCompositor->getMonitorFromName(std::string(OUTPUT->name))) { if (g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Monitor with name %s already exists, not adding as new!", OUTPUT->name); Debug::log(WARN, "Recovering from an unsafe state. May you be lucky.");
return;
} }
// add it to real // add it to real
const auto PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>()); std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
wlr_output_init_render(OUTPUT, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer); for (auto& rm : g_pCompositor->m_vRealMonitors) {
if (rm->szName == OUTPUT->name) {
PNEWMONITORWRAP = &rm;
Debug::log(LOG, "Recovering a removed monitor.");
break;
}
}
if (!PNEWMONITORWRAP) {
Debug::log(LOG, "Adding completely new monitor.");
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
(*PNEWMONITORWRAP)->ID = g_pCompositor->getNextAvailableMonitorID();
}
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
PNEWMONITOR->output = OUTPUT; PNEWMONITOR->output = OUTPUT;
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP; PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
PNEWMONITOR->onConnect(false); PNEWMONITOR->onConnect(false);
if (!pMostHzMonitor || PNEWMONITOR->refreshRate > pMostHzMonitor->refreshRate) if ((!pMostHzMonitor || PNEWMONITOR->refreshRate > pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
pMostHzMonitor = PNEWMONITOR; pMostHzMonitor = PNEWMONITOR;
// ready to process cuz we have a monitor // ready to process cuz we have a monitor
g_pCompositor->m_bReadyToProcess = true; if (PNEWMONITOR->m_bEnabled) {
g_pCompositor->m_bReadyToProcess = true;
g_pCompositor->m_bUnsafeState = false;
}
} }
void Events::listener_monitorFrame(void* owner, void* data) { void Events::listener_monitorFrame(void* owner, void* data) {
CMonitor* const PMONITOR = (CMonitor*)owner; CMonitor* const PMONITOR = (CMonitor*)owner;
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive) { if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!"); Debug::log(WARN, "Attempted to render frame on inactive session!");
return; // cannot draw on session inactive (different tty) return; // cannot draw on session inactive (different tty)
} }
if (!PMONITOR->m_bEnabled) if (!PMONITOR->m_bEnabled)
return; return;
@@ -174,18 +188,18 @@ void Events::listener_monitorFrame(void* owner, void* data) {
} }
// if we have no tracking or full tracking, invalidate the entire monitor // if we have no tracking or full tracking, invalidate the entire monitor
if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0 || damageBlinkCleanup > 0) { if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0 || damageBlinkCleanup > 0 || PMONITOR->isMirror() /* why??? */) {
pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y); pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x * 10, (int)PMONITOR->vecTransformedSize.y * 10); // wot?
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage); pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
} else { } else {
static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue; static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
// if we use blur we need to expand the damage for proper blurring // if we use blur we need to expand the damage for proper blurring
if (*PBLURENABLED == 1) { if (*PBLURENABLED == 1) {
// TODO: can this be optimized? // TODO: can this be optimized?
static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue; static auto *const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue; static auto *const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
const auto BLURRADIUS = *PBLURSIZE * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think. const auto BLURRADIUS = *PBLURSIZE * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think.
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage); pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
@@ -202,44 +216,49 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (PMONITOR->forceFullFrames > 10) if (PMONITOR->forceFullFrames > 10)
PMONITOR->forceFullFrames = 0; PMONITOR->forceFullFrames = 0;
} }
// TODO: this is getting called with extents being 0,0,0,0 should it be? // TODO: this is getting called with extents being 0,0,0,0 should it be?
// potentially can save on resources. // potentially can save on resources.
g_pHyprOpenGL->begin(PMONITOR, &damage); g_pHyprOpenGL->begin(PMONITOR, &damage);
g_pHyprOpenGL->clear(CColor(17, 17, 17, 255));
g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now); if (PMONITOR->isMirror()) {
g_pHyprOpenGL->renderMirrored();
} else {
g_pHyprOpenGL->clear(CColor(17, 17, 17, 255));
g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
// if correct monitor draw hyprerror g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now);
if (PMONITOR->ID == 0)
g_pHyprError->draw();
// for drawing the debug overlay // if correct monitor draw hyprerror
if (PMONITOR->ID == 0 && *PDEBUGOVERLAY == 1) { if (PMONITOR->ID == 0)
startRenderOverlay = std::chrono::high_resolution_clock::now(); g_pHyprError->draw();
g_pDebugOverlay->draw();
endRenderOverlay = std::chrono::high_resolution_clock::now(); // for drawing the debug overlay
if (PMONITOR->ID == 0 && *PDEBUGOVERLAY == 1) {
startRenderOverlay = std::chrono::high_resolution_clock::now();
g_pDebugOverlay->draw();
endRenderOverlay = std::chrono::high_resolution_clock::now();
}
if (*PDAMAGEBLINK && damageBlinkCleanup == 0) {
wlr_box monrect = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
g_pHyprOpenGL->renderRect(&monrect, CColor(255, 0, 255, 100), 0);
damageBlinkCleanup = 1;
} else if (*PDAMAGEBLINK) {
damageBlinkCleanup++;
if (damageBlinkCleanup > 3)
damageBlinkCleanup = 0;
}
wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
wlr_output_render_software_cursors(PMONITOR->output, NULL);
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
} }
if (*PDAMAGEBLINK && damageBlinkCleanup == 0) {
wlr_box monrect = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
g_pHyprOpenGL->renderRect(&monrect, CColor(255,0,255,100), 0);
damageBlinkCleanup = 1;
} else if (*PDAMAGEBLINK) {
damageBlinkCleanup++;
if (damageBlinkCleanup > 3)
damageBlinkCleanup = 0;
}
wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y);
wlr_output_render_software_cursors(PMONITOR->output, NULL);
wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
g_pHyprOpenGL->end(); g_pHyprOpenGL->end();
// calc frame damage // calc frame damage
@@ -256,10 +275,15 @@ void Events::listener_monitorFrame(void* owner, void* data) {
pixman_region32_union(&frameDamage, &frameDamage, &damage); pixman_region32_union(&frameDamage, &frameDamage, &damage);
wlr_output_set_damage(PMONITOR->output, &frameDamage); wlr_output_set_damage(PMONITOR->output, &frameDamage);
if (!PMONITOR->mirrors.empty())
g_pHyprRenderer->damageMirrorsWith(PMONITOR, &frameDamage);
pixman_region32_fini(&frameDamage); pixman_region32_fini(&frameDamage);
pixman_region32_fini(&damage); pixman_region32_fini(&damage);
wlr_output_commit(PMONITOR->output); if (!wlr_output_commit(PMONITOR->output))
return;
if (*PDAMAGEBLINK || *PNOVFR) if (*PDAMAGEBLINK || *PNOVFR)
g_pCompositor->scheduleFrameForMonitor(PMONITOR); g_pCompositor->scheduleFrameForMonitor(PMONITOR);
@@ -293,20 +317,23 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
pMonitor->onDisconnect(); pMonitor->onDisconnect();
// cleanup // cleanup if not unsafe
g_pCompositor->m_vRealMonitors.erase(std::remove_if(g_pCompositor->m_vRealMonitors.begin(), g_pCompositor->m_vRealMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; }));
if (pMostHzMonitor == pMonitor) { if (!g_pCompositor->m_bUnsafeState) {
int mostHz = 0; g_pCompositor->m_vRealMonitors.erase(std::remove_if(g_pCompositor->m_vRealMonitors.begin(), g_pCompositor->m_vRealMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; }));
CMonitor* pMonitorMostHz = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) { if (pMostHzMonitor == pMonitor) {
if (m->refreshRate > mostHz) { int mostHz = 0;
pMonitorMostHz = m.get(); CMonitor* pMonitorMostHz = nullptr;
mostHz = m->refreshRate;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->refreshRate > mostHz) {
pMonitorMostHz = m.get();
mostHz = m->refreshRate;
}
} }
}
pMostHzMonitor = pMonitorMostHz; pMostHzMonitor = pMonitorMostHz;
}
} }
} }

View File

@@ -18,18 +18,22 @@
void addPopupGlobalCoords(void* pPopup, int* x, int* y) { void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
SXDGPopup *const PPOPUP = (SXDGPopup*)pPopup; SXDGPopup *const PPOPUP = (SXDGPopup*)pPopup;
auto curPopup = PPOPUP;
int px = 0; int px = 0;
int py = 0; int py = 0;
auto curPopup = PPOPUP;
while (true) { while (true) {
px += curPopup->popup->current.geometry.x; px += curPopup->popup->current.geometry.x;
py += curPopup->popup->current.geometry.y; py += curPopup->popup->current.geometry.y;
// fix oversized fucking popups if (curPopup == PPOPUP && PPOPUP->parentWindow) {
// kill me px -= curPopup->popup->base->current.geometry.x;
if (curPopup->pSurfaceTree && curPopup->pSurfaceTree->pSurface && !curPopup->parentPopup) { py -= curPopup->popup->base->current.geometry.y;
const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->pSurfaceTree->pSurface->input_region); }
if (curPopup->popup && !curPopup->parentPopup && !curPopup->parentWindow) {
const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->popup->base->surface->input_region);
px -= EXTENTSSURFACE->x1; px -= EXTENTSSURFACE->x1;
py -= EXTENTSSURFACE->y1; py -= EXTENTSSURFACE->y1;
} }
@@ -59,7 +63,7 @@ void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
const auto PMONITOR = g_pCompositor->m_pLastMonitor; const auto PMONITOR = g_pCompositor->m_pLastMonitor;
wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->vecTransformedSize.x, .height = PMONITOR->vecTransformedSize.y}; wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->vecSize.x, .height = PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(popup, &box); wlr_xdg_popup_unconstrain_from_box(popup, &box);
@@ -104,12 +108,9 @@ void Events::listener_newPopupXDG(void* owner, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
wlr_box geom;
wlr_xdg_surface_get_geometry(PWINDOW->m_uSurface.xdg, &geom);
PNEWPOPUP->popup = WLRPOPUP; PNEWPOPUP->popup = WLRPOPUP;
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x - geom.x; PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x;
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y - geom.y; PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y;
PNEWPOPUP->parentWindow = PWINDOW; PNEWPOPUP->parentWindow = PWINDOW;
PNEWPOPUP->monitor = PMONITOR; PNEWPOPUP->monitor = PMONITOR;
createNewPopup(WLRPOPUP, PNEWPOPUP); createNewPopup(WLRPOPUP, PNEWPOPUP);
@@ -119,7 +120,7 @@ void Events::listener_newPopupFromPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner; SXDGPopup* PPOPUP = (SXDGPopup*)owner;
ASSERT(PPOPUP); ASSERT(PPOPUP);
if (PPOPUP->parentWindow) if (PPOPUP->parentWindow)
Debug::log(LOG, "New popup created from XDG Window popup %x -> %s", PPOPUP, PPOPUP->parentWindow->m_szTitle.c_str()); Debug::log(LOG, "New popup created from XDG Window popup %x -> %s", PPOPUP, PPOPUP->parentWindow->m_szTitle.c_str());
else else
@@ -151,7 +152,10 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0; int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly); addPopupGlobalCoords(PPOPUP, &lx, &ly);
g_pHyprRenderer->damageBox(lx, ly, PPOPUP->popup->current.geometry.width, PPOPUP->popup->current.geometry.width); wlr_box extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree); Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree);
} }
@@ -167,7 +171,10 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0; int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly); addPopupGlobalCoords(PPOPUP, &lx, &ly);
g_pHyprRenderer->damageBox(lx, ly, PPOPUP->popup->current.geometry.width, PPOPUP->popup->current.geometry.width); wlr_box extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
PPOPUP->pSurfaceTree = nullptr; PPOPUP->pSurfaceTree = nullptr;
} }
@@ -194,4 +201,4 @@ void Events::listener_destroyPopupXDG(void* owner, void* data) {
} }
g_pCompositor->m_vXDGPopups.erase(std::remove_if(g_pCompositor->m_vXDGPopups.begin(), g_pCompositor->m_vXDGPopups.end(), [&](std::unique_ptr<SXDGPopup>& el) { return el.get() == PPOPUP; })); g_pCompositor->m_vXDGPopups.erase(std::remove_if(g_pCompositor->m_vXDGPopups.begin(), g_pCompositor->m_vXDGPopups.end(), [&](std::unique_ptr<SXDGPopup>& el) { return el.get() == PPOPUP; }));
} }

View File

@@ -48,8 +48,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
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 PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
static auto *const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
static auto *const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); const 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->specialWorkspaceOpen ? g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_iMonitorID = PMONITOR->ID;
PWINDOW->m_bMappedX11 = true; PWINDOW->m_bMappedX11 = true;
@@ -68,9 +71,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM); g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
// Foreign Toplevel // Foreign Toplevel
PWINDOW->m_phForeignToplevel = wlr_foreign_toplevel_handle_v1_create(g_pCompositor->m_sWLRToplevelMgr); PWINDOW->createToplevelHandle();
// TODO: handle foreign events (requests)
wlr_foreign_toplevel_handle_v1_set_app_id(PWINDOW->m_phForeignToplevel, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
// checks if the window wants borders and sets the appriopriate flag // checks if the window wants borders and sets the appriopriate flag
g_pXWaylandManager->checkBorders(PWINDOW); g_pXWaylandManager->checkBorders(PWINDOW);
@@ -87,6 +88,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bRequestsFloat = true; PWINDOW->m_bRequestsFloat = true;
} }
PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2);
if (PWORKSPACE->m_bDefaultFloating) if (PWORKSPACE->m_bDefaultFloating)
PWINDOW->m_bIsFloating = true; PWINDOW->m_bIsFloating = true;
@@ -97,17 +100,21 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height); PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
} }
CWindow* pFullscreenWindow = nullptr;
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) { if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PFULLWINDOW, FULLSCREEN_FULL, false); pFullscreenWindow = PFULLWINDOW;
g_pXWaylandManager->setWindowFullscreen(PFULLWINDOW, PFULLWINDOW->m_bIsFullscreen); g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, PWORKSPACE->m_efFullscreenMode);
} }
// window rules // window rules
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW); const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
std::string requestedWorkspace = ""; std::string requestedWorkspace = "";
bool workspaceSilent = false; bool workspaceSilent = false;
bool requestsFullscreen = false; bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen);
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) {
@@ -118,13 +125,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_iMonitorID = PMONITOR->ID;
} else { } else {
const long int MONITOR = std::stoi(MONITORSTR); const long int MONITOR = std::stoi(MONITORSTR);
if (MONITOR >= (long int)g_pCompositor->m_vMonitors.size() || MONITOR < (long int)0) if (!g_pCompositor->getMonitorFromID(MONITOR))
PWINDOW->m_iMonitorID = 0; PWINDOW->m_iMonitorID = 0;
else else
PWINDOW->m_iMonitorID = MONITOR; PWINDOW->m_iMonitorID = MONITOR;
} }
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace; PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
Debug::log(ERR, "Rule monitor, applying to window %x -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID); Debug::log(ERR, "Rule monitor, applying to window %x -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID);
} catch (std::exception& e) { } catch (std::exception& e) {
@@ -140,6 +148,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;
@@ -151,10 +162,22 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bNoFocus = true; PWINDOW->m_bNoFocus = true;
} else if (r.szRule == "noblur") { } else if (r.szRule == "noblur") {
PWINDOW->m_sAdditionalConfigData.forceNoBlur = true; PWINDOW->m_sAdditionalConfigData.forceNoBlur = true;
} else if (r.szRule == "noborder") {
PWINDOW->m_sAdditionalConfigData.forceNoBorder = true;
} else if (r.szRule == "noshadow") {
PWINDOW->m_sAdditionalConfigData.forceNoShadow = true;
} else if (r.szRule == "fullscreen") { } else if (r.szRule == "fullscreen") {
requestsFullscreen = true; requestsFullscreen = true;
} else if (r.szRule == "opaque") { } else if (r.szRule == "opaque") {
PWINDOW->m_sAdditionalConfigData.forceOpaque = true; PWINDOW->m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule == "windowdance") {
PWINDOW->m_sAdditionalConfigData.windowDanceCompat = true;
} else if (r.szRule == "forceinput") {
PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true;
} else if (r.szRule == "pin") {
PWINDOW->m_bPinned = true;
} else if (r.szRule == "noanim") {
PWINDOW->m_sAdditionalConfigData.forceNoAnims = true;
} else if (r.szRule.find("rounding") == 0) { } else if (r.szRule.find("rounding") == 0) {
try { try {
PWINDOW->m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); PWINDOW->m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
@@ -181,19 +204,28 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
} }
// disallow tiled pinned
if (PWINDOW->m_bPinned && !PWINDOW->m_bIsFloating)
PWINDOW->m_bPinned = false;
if (requestedWorkspace != "") { if (requestedWorkspace != "") {
// process requested workspace // process requested workspace
if (requestedWorkspace.contains(' ')) { if (requestedWorkspace.contains(' ')) {
// check for silent // check for silent
if (requestedWorkspace.contains("silent")) { if (requestedWorkspace.contains("silent")) {
workspaceSilent = true; workspaceSilent = true;
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))
shouldFocus = true;
}
if (requestedWorkspace == "special") { if (requestedWorkspace == "special") {
workspaceSilent = true; workspaceSpecial = true;
} workspaceSilent = true;
} }
if (!workspaceSilent) { if (!workspaceSilent) {
@@ -204,6 +236,44 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
} }
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 = SPECIAL_WORKSPACE_ID;
} 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;
}
}
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
PWINDOW->m_bCreatedOverFullscreen = true; PWINDOW->m_bCreatedOverFullscreen = true;
@@ -216,32 +286,80 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(" ")); const auto SIZEXSTR = VALUE.substr(0, VALUE.find(" "));
const auto SIZEYSTR = VALUE.substr(VALUE.find(" ") + 1); const auto SIZEYSTR = VALUE.substr(VALUE.find(" ") + 1);
const auto SIZEX = !SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stoi(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.x; const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW);
const auto SIZEY = !SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stoi(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.y;
const auto SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) : (!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stoi(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
const auto SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) : (!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stoi(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
Debug::log(LOG, "Rule size, applying to window %x", PWINDOW); Debug::log(LOG, "Rule size, applying to window %x", PWINDOW);
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("minsize") == 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::max((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::max((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 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) { } else if (r.szRule.find("move") == 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 POSXSTR = VALUE.substr(0, VALUE.find(" "));
const auto POSYSTR = VALUE.substr(VALUE.find(" ") + 1); const auto POSYSTR = VALUE.substr(VALUE.find(" ") + 1);
const auto POSX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.x; int posX = 0;
const auto POSY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01f * PMONITOR->vecSize.y; 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);
} else {
posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stoi(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.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);
} else {
posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stoi(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.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());
} }
@@ -253,37 +371,51 @@ void Events::listener_mapWindow(void* owner, void* data) {
// set the pseudo size to the GOAL of our current size // set the pseudo size to the GOAL of our current size
// because the windows are animated on RealSize // because the windows are animated on RealSize
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv(); PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv();
}
else { g_pCompositor->moveWindowToTop(PWINDOW);
} 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
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10,10); PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10,10);
} }
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus && PWINDOW->m_iX11Type != 2) { const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow;
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) {
PWINDOW->m_bNoFocus = false;
PWINDOW->m_bNoInitialFocus = false;
PWINDOW->m_bX11ShouldntFocus = false;
}
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);
} else PWINDOW->m_fDimPercent.setValueAndWarp(*PDIMSTRENGTH);
} else {
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(0);
}
Debug::log(LOG, "Window got assigned a surfaceTreeNode %x", PWINDOW->m_pSurfaceTree); Debug::log(LOG, "Window got assigned a surfaceTreeNode %x", PWINDOW->m_pSurfaceTree);
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xdg->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xdg->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestMove.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_move, &Events::listener_requestMove, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_requestMove.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_move, &Events::listener_requestMove, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestResize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_resize, &Events::listener_requestResize, PWINDOW, "XDG Window Late"); PWINDOW->hyprListener_requestResize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_resize, &Events::listener_requestResize, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XDG Window Late");
} else { } else {
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, "XWayland Window Late");
PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW, "XWayland Window Late"); PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW, "XWayland Window Late");
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");
} }
@@ -296,24 +428,11 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto TIMER = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, setAnimToMove, PWINDOW); const auto TIMER = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, setAnimToMove, PWINDOW);
wl_event_source_timer_update(TIMER, PWINDOW->m_vRealPosition.getDurationLeftMs() + 5); wl_event_source_timer_update(TIMER, PWINDOW->m_vRealPosition.getDurationLeftMs() + 5);
if (workspaceSilent) {
// move the window
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!");
}
}
if (requestsFullscreen) { 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);
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PFULLWINDOW, FULLSCREEN_FULL, false); g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
g_pXWaylandManager->setWindowFullscreen(PFULLWINDOW, PFULLWINDOW->m_bIsFullscreen);
} }
PWINDOW->m_vRealPosition.warp(); PWINDOW->m_vRealPosition.warp();
@@ -322,12 +441,89 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL);
} }
if (pFullscreenWindow && workspaceSilent) {
g_pCompositor->setWindowFullscreen(pFullscreenWindow, true, PWORKSPACE->m_efFullscreenMode);
}
// recheck idle inhibitors // recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(g_pXWaylandManager->getWindowSurface(PWINDOW), addViewCoords, PWINDOW, PWINDOW); PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(g_pXWaylandManager->getWindowSurface(PWINDOW), addViewCoords, PWINDOW, PWINDOW);
PWINDOW->updateToplevel();
if (!shouldFocus) {
if (g_pCompositor->windowValidMapped(PFOCUSEDWINDOWPREV)) {
g_pCompositor->focusWindow(PFOCUSEDWINDOWPREV);
PFOCUSEDWINDOWPREV->updateWindowDecos(); // need to for some reason i cba to find out why
} else if (!PFOCUSEDWINDOWPREV)
g_pCompositor->focusWindow(nullptr);
}
// verify swallowing
if (*PSWALLOW) {
// don't swallow ourselves
std::regex rgx(*PSWALLOWREGEX);
if (!std::regex_match(g_pXWaylandManager->getAppIDClass(PWINDOW), rgx)) {
// check parent
int ppid = getPPIDof(PWINDOW->getPID());
int curppid = 0;
for (int i = 0; i < 5; ++i) {
curppid = getPPIDof(ppid);
if (curppid < 10) {
break;
}
ppid = curppid;
}
if (ppid) {
// get window by pid
std::vector<CWindow*> found;
CWindow* finalFound = nullptr;
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->isHidden())
continue;
if (w->getPID() == ppid) {
found.push_back(w.get());
}
}
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);
}
}
}
}
}
Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, PWINDOW->m_vRealSize.goalv().x, PWINDOW->m_vRealSize.goalv().y); Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, PWINDOW->m_vRealSize.goalv().x, PWINDOW->m_vRealSize.goalv().y);
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", getFormat("%x,%s,%s,%s", PWINDOW, workspaceID.c_str(), g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), PWINDOW->m_szTitle.c_str())});
} }
void Events::listener_unmapWindow(void* owner, void* data) { void Events::listener_unmapWindow(void* owner, void* data) {
@@ -335,16 +531,18 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "Window %x unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str()); Debug::log(LOG, "Window %x unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%x", PWINDOW)});
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
Debug::log(LOG, "Unregistered late callbacks XDG"); Debug::log(LOG, "Unregistered late callbacks XDG");
PWINDOW->hyprListener_commitWindow.removeCallback(); PWINDOW->hyprListener_commitWindow.removeCallback();
PWINDOW->hyprListener_setTitleWindow.removeCallback(); PWINDOW->hyprListener_setTitleWindow.removeCallback();
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
PWINDOW->hyprListener_newPopupXDG.removeCallback(); PWINDOW->hyprListener_newPopupXDG.removeCallback();
PWINDOW->hyprListener_requestMaximize.removeCallback(); PWINDOW->hyprListener_requestMaximize.removeCallback();
PWINDOW->hyprListener_requestMinimize.removeCallback(); PWINDOW->hyprListener_requestMinimize.removeCallback();
PWINDOW->hyprListener_requestMove.removeCallback(); PWINDOW->hyprListener_requestMove.removeCallback();
PWINDOW->hyprListener_requestResize.removeCallback(); PWINDOW->hyprListener_requestResize.removeCallback();
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
} else { } else {
Debug::log(LOG, "Unregistered late callbacks XWL"); Debug::log(LOG, "Unregistered late callbacks XWL");
PWINDOW->hyprListener_fullscreenWindow.removeCallback(); PWINDOW->hyprListener_fullscreenWindow.removeCallback();
@@ -352,17 +550,28 @@ 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) {
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, false); g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen);
} }
// Allow the renderer to catch the last frame. // Allow the renderer to catch the last frame.
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW); g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
// swallowing
if (PWINDOW->m_pSwallowed && g_pCompositor->windowExists(PWINDOW->m_pSwallowed)) {
PWINDOW->m_pSwallowed->setHidden(false);
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed);
PWINDOW->m_pSwallowed = nullptr;
}
bool wasLastWindow = false;
if (PWINDOW == g_pCompositor->m_pLastWindow) { if (PWINDOW == g_pCompositor->m_pLastWindow) {
wasLastWindow = true;
g_pCompositor->m_pLastWindow = nullptr; g_pCompositor->m_pLastWindow = nullptr;
g_pCompositor->m_pLastFocus = nullptr; g_pCompositor->m_pLastFocus = nullptr;
} }
@@ -380,12 +589,30 @@ void Events::listener_unmapWindow(void* owner, void* data) {
// do this after onWindowRemoved because otherwise it'll think the window is invalid // do this after onWindowRemoved because otherwise it'll think the window is invalid
PWINDOW->m_bIsMapped = false; PWINDOW->m_bIsMapped = false;
// refocus on a new window // refocus on a new window if needed
g_pInputManager->refocus(); if (wasLastWindow) {
const auto PWINDOWCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW);
Debug::log(LOG, "On closed window, new focused candidate is %x", PWINDOWCANDIDATE);
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow) {
if (!PWINDOWCANDIDATE)
g_pInputManager->refocus();
else
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
} else {
g_pInputManager->refocus();
}
} else {
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
}
// update lastwindow after focus
PWINDOW->onUnmap();
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %x", PWINDOW); Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %x", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree); SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
PWINDOW->m_pSurfaceTree = nullptr; PWINDOW->m_pSurfaceTree = nullptr;
PWINDOW->m_bFadingOut = true; PWINDOW->m_bFadingOut = true;
@@ -402,26 +629,28 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.vec() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.vec() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
// anims // anims
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true); g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true);
PWINDOW->m_fAlpha = 0.f; PWINDOW->m_fAlpha = 0.f;
// Destroy Foreign Toplevel // Destroy Foreign Toplevel
wlr_foreign_toplevel_handle_v1_destroy(PWINDOW->m_phForeignToplevel); PWINDOW->destroyToplevelHandle();
PWINDOW->m_phForeignToplevel = nullptr;
// recheck idle inhibitors // recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
// force report all sizes (QT sometimes has an issue with this)
g_pCompositor->forceReportSizesToWindowsOnWorkspace(PWINDOW->m_iWorkspaceID);
} }
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);
// Debug::log(LOG, "Window %x committed", PWINDOW); // SPAM! // Debug::log(LOG, "Window %x committed", PWINDOW); // SPAM!
} }
@@ -465,8 +694,7 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
if (PWINDOW == g_pCompositor->m_pLastWindow) // if it's the active, let's post an event to update others if (PWINDOW == g_pCompositor->m_pLastWindow) // if it's the active, let's post an event to update others
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle});
if (PWINDOW->m_phForeignToplevel) PWINDOW->updateToplevel();
wlr_foreign_toplevel_handle_v1_set_title(PWINDOW->m_phForeignToplevel, PWINDOW->m_szTitle.c_str());
Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str()); Debug::log(LOG, "Window %x set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str());
} }
@@ -474,32 +702,66 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
void Events::listener_fullscreenWindow(void* owner, void* data) { void Events::listener_fullscreenWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bIsMapped) {
PWINDOW->m_bWantsInitialFullscreen = true;
return;
}
if (PWINDOW->isHidden())
return;
if (!PWINDOW->m_bIsX11) { if (!PWINDOW->m_bIsX11) {
const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested; const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested;
if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen) if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen)
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, REQUESTED->fullscreen); g_pCompositor->setWindowFullscreen(PWINDOW, REQUESTED->fullscreen, FULLSCREEN_FULL);
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg); wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
} else { } else {
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, !PWINDOW->m_bIsFullscreen); if (!PWINDOW->m_uSurface.xwayland->mapped)
return;
g_pCompositor->setWindowFullscreen(PWINDOW, PWINDOW->m_uSurface.xwayland->fullscreen, FULLSCREEN_FULL);
} }
PWINDOW->updateToplevel();
Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen); Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen);
g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen);
} }
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) {
@@ -511,22 +773,22 @@ void Events::listener_configureX11(void* owner, void* data) {
const auto E = (wlr_xwayland_surface_configure_event*)data; const auto E = (wlr_xwayland_surface_configure_event*)data;
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
if (!PWINDOW->m_bIsFloating) { if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec()); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.vec());
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
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));
@@ -541,7 +803,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);
@@ -551,20 +814,20 @@ 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 (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);
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y)); PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y));
@@ -624,12 +887,35 @@ 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;
// ignore Debug::log(LOG, "Maximize request for %x", PWINDOW);
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
if (!PWINDOW->m_bIsX11) {
const auto EV = (wlr_foreign_toplevel_handle_v1_maximized_event*)data;
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) {
@@ -644,4 +930,4 @@ void Events::listener_requestResize(void* owner, void* data) {
// ignore // ignore
wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg); wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg);
} }

View File

@@ -59,5 +59,5 @@ void CAnimatedVariable::unregister() {
} }
int CAnimatedVariable::getDurationLeftMs() { int CAnimatedVariable::getDurationLeftMs() {
return std::clamp((int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0, INT_MAX); 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);
} }

View File

@@ -125,7 +125,7 @@ public:
switch (m_eVarType) { switch (m_eVarType) {
case AVARTYPE_FLOAT: case AVARTYPE_FLOAT:
return m_fValue != m_fGoal; return m_fValue != m_fGoal;
case AVARTYPE_VECTOR: case AVARTYPE_VECTOR:
return m_vValue != m_vGoal; return m_vValue != m_vGoal;
case AVARTYPE_COLOR: case AVARTYPE_COLOR:
return m_cValue != m_cGoal; return m_cValue != m_cGoal;
@@ -198,4 +198,4 @@ private:
friend class CAnimationManager; friend class CAnimationManager;
friend class CWorkspace; friend class CWorkspace;
friend struct SLayerSurface; friend struct SLayerSurface;
}; };

View File

@@ -1,9 +1,7 @@
#include "Color.hpp" #include "Color.hpp"
#include "../defines.hpp" #include "../defines.hpp"
CColor::CColor() { CColor::CColor() { }
}
CColor::CColor(float r, float g, float b, float a) { CColor::CColor(float r, float g, float b, float a) {
this->r = r; this->r = r;

View File

@@ -23,8 +23,8 @@ public:
CColor operator* (const float& v) const { CColor operator* (const float& v) const {
return CColor(r * v, g * v, b * v, a * v); return CColor(r * v, g * v, b * v, a * v);
} }
bool operator==(const CColor& c2) const { bool operator==(const CColor& c2) const {
return r == c2.r && g == c2.g && b == c2.b && a == c2.a; return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
} }
}; };

View File

@@ -40,10 +40,32 @@ static const float transforms[][9] = {{
}, },
}; };
std::string absolutePath(const std::string& rawpath, const std::string& currentPath) {
auto value = rawpath;
if (value[0] == '.') {
auto currentDir = currentPath.substr(0, currentPath.find_last_of('/'));
if (value[1] == '.') {
auto parentDir = currentDir.substr(0, currentDir.find_last_of('/'));
value.replace(0, 2, parentDir);
} else {
value.replace(0, 1, currentDir);
}
}
if (value[0] == '~') {
static const char* const ENVHOME = getenv("HOME");
value.replace(0, 1, std::string(ENVHOME));
}
return value;
}
void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) { void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) {
ASSERT(pSignal); ASSERT(pSignal);
ASSERT(pListener); ASSERT(pListener);
wl_signal_add(pSignal, pListener); wl_signal_add(pSignal, pListener);
Debug::log(LOG, "Registered signal for owner %x: %x -> %x (owner: %s)", pOwner, pSignal, pListener, ownerString.c_str()); Debug::log(LOG, "Registered signal for owner %x: %x -> %x (owner: %s)", pOwner, pSignal, pListener, ownerString.c_str());
@@ -53,35 +75,6 @@ void handleNoop(struct wl_listener *listener, void *data) {
// Do nothing // Do nothing
} }
void wlr_signal_emit_safe(struct wl_signal *signal, void *data) {
struct wl_listener cursor;
struct wl_listener end;
/* Add two special markers: one cursor and one end marker. This way, we know
* that we've already called listeners on the left of the cursor and that we
* don't want to call listeners on the right of the end marker. The 'it'
* function can remove any element it wants from the list without troubles.
* wl_list_for_each_safe tries to be safe but it fails: it works fine
* if the current item is removed, but not if the next one is. */
wl_list_insert(&signal->listener_list, &cursor.link);
cursor.notify = handleNoop;
wl_list_insert(signal->listener_list.prev, &end.link);
end.notify = handleNoop;
while (cursor.link.next != &end.link) {
struct wl_list *pos = cursor.link.next;
struct wl_listener *l = wl_container_of(pos, l, link);
wl_list_remove(&cursor.link);
wl_list_insert(pos, &cursor.link);
l->notify(l, data);
}
wl_list_remove(&cursor.link);
wl_list_remove(&end.link);
}
std::string getFormat(const char *fmt, ...) { std::string getFormat(const char *fmt, ...) {
char* outputStr = nullptr; char* outputStr = nullptr;
@@ -127,14 +120,18 @@ void scaleBox(wlr_box* box, float scale) {
} }
std::string removeBeginEndSpacesTabs(std::string str) { std::string removeBeginEndSpacesTabs(std::string str) {
while (str[0] == ' ' || str[0] == '\t') { int countBefore = 0;
str = str.substr(1); while (str[countBefore] == ' ' || str[countBefore] == '\t') {
countBefore++;
} }
while (str.length() != 0 && (str[str.length() - 1] == ' ' || str[str.length() - 1] == '\t')) { int countAfter = 0;
str = str.substr(0, str.length() - 1); while (str.length() != 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
countAfter++;
} }
str = str.substr(countBefore, str.length() - countBefore - countAfter);
return str; return str;
} }
@@ -177,7 +174,28 @@ float getPlusMinusKeywordResult(std::string source, float relative) {
} }
bool isNumber(const std::string& str, bool allowfloat) { bool isNumber(const std::string& str, bool allowfloat) {
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
std::string copy = str;
if (*copy.begin() == '-')
copy = copy.substr(1);
if (copy.empty())
return false;
bool point = !allowfloat;
for (auto& c : copy) {
if (c == '.') {
if (point)
return false;
point = true;
break;
}
if (!std::isdigit(c))
return false;
}
return true;
} }
bool isDirection(const std::string& arg) { bool isDirection(const std::string& arg) {
@@ -199,7 +217,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
} }
outName = WORKSPACENAME; outName = WORKSPACENAME;
} else { } else {
if (in[0] == 'm' || in[0] == 'e') { 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';
if (!g_pCompositor->m_pLastMonitor) { if (!g_pCompositor->m_pLastMonitor) {
@@ -219,15 +237,18 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
while (remains != 0) { while (remains != 0) {
if (remains < 0) if (remains < 0)
searchID--; searchID--;
else else
searchID++; searchID++;
if (g_pCompositor->workspaceIDOutOfBounds(searchID)){ if (g_pCompositor->workspaceIDOutOfBounds(searchID)){
// means we need to wrap around // means we need to wrap around
int lowestID = 99999; int lowestID = 99999;
int highestID = -99999; int highestID = -99999;
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iID == SPECIAL_WORKSPACE_ID)
continue;
if (w->m_iID < lowestID) if (w->m_iID < lowestID)
lowestID = w->m_iID; lowestID = w->m_iID;
@@ -237,7 +258,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
if (remains < 0) if (remains < 0)
searchID = highestID; searchID = highestID;
else else
searchID = lowestID; searchID = lowestID;
} }
@@ -257,24 +278,32 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
outName = g_pCompositor->getWorkspaceByID(currentID)->m_szName; outName = g_pCompositor->getWorkspaceByID(currentID)->m_szName;
} else { } else {
if (g_pCompositor->m_pLastMonitor) if (in[0] == '+' || in[0] == '-') {
result = std::clamp((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1, INT_MAX); if (g_pCompositor->m_pLastMonitor)
else if (isNumber(in)) result = std::max((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1);
result = std::clamp(std::stoi(in), 1, INT_MAX); else {
Debug::log(ERR, "Relative workspace on no mon!");
result = INT_MAX;
}
} else if (isNumber(in))
result = std::max(std::stoi(in), 1);
else { else {
Debug::log(ERR, "Relative workspace on no mon!"); // maybe name
result = INT_MAX; const auto PWORKSPACE = g_pCompositor->getWorkspaceByName(in);
if (PWORKSPACE)
result = PWORKSPACE->m_iID;
} }
outName = std::to_string(result); outName = std::to_string(result);
} }
} }
return result; return result;
} }
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) { float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) {
const float DX = std::max((double)0, std::max(p1.x - vec.x, vec.x - p2.x)); const float DX = std::max({0.0, p1.x - vec.x, vec.x - p2.x});
const float DY = std::max((double)0, std::max(p1.y - vec.y, vec.y - p2.y)); const float DY = std::max({0.0, p1.y - vec.y, vec.y - p2.y});
return DX * DX + DY * DY; return DX * DX + DY * DY;
} }
@@ -303,6 +332,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:");
@@ -319,8 +357,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]);
@@ -329,3 +367,38 @@ void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
// Identity // Identity
mat[8] = 1.0f; mat[8] = 1.0f;
} }
int64_t getPPIDof(int64_t pid) {
std::string dir = "/proc/" + std::to_string(pid) + "/status";
FILE* infile;
infile = fopen(dir.c_str(), "r");
if (!infile)
return 0;
char* line = nullptr;
size_t len = 0;
ssize_t len2 = 0;
std::string pidstr;
while ((len2 = getline(&line, &len, infile)) != -1) {
if (strstr(line, "PPid:")) {
pidstr = std::string(line, len2);
const auto tabpos = pidstr.find_last_of('\t');
if (tabpos != std::string::npos)
pidstr = pidstr.substr(tabpos);
break;
}
}
fclose(infile);
if (line)
free(line);
try {
return std::stoll(pidstr);
} catch (std::exception& e) {
return 0;
}
}

View File

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

View File

@@ -3,36 +3,95 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
void CMonitor::onConnect(bool noRule) { void CMonitor::onConnect(bool noRule) {
if (m_bEnabled)
return;
szName = output->name;
// get monitor rule that matches // get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name); SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this); hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this); hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
// if it's disabled, disable and ignore // if it's disabled, disable and ignore
if (monitorRule.disabled) { if (monitorRule.disabled) {
wlr_output_enable_adaptive_sync(output, 1);
wlr_output_set_scale(output, 1);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
auto PREFSTATE = wlr_output_preferred_mode(output);
if (!PREFSTATE) {
wlr_output_mode* mode;
wl_list_for_each(mode, &output->modes, link) {
wlr_output_set_mode(output, PREFSTATE);
if (!wlr_output_test(output))
continue;
PREFSTATE = mode;
break;
}
}
if (PREFSTATE)
wlr_output_set_mode(output, PREFSTATE);
else
Debug::log(WARN, "No mode found for disabled output %s", output->name);
wlr_output_enable(output, 0); wlr_output_enable(output, 0);
wlr_output_commit(output);
if (!wlr_output_commit(output)) {
Debug::log(ERR, "Couldn't commit disabled state on output %s", output->name);
}
Events::listener_change(nullptr, nullptr);
m_bEnabled = false;
hyprListener_monitorFrame.removeCallback(); hyprListener_monitorFrame.removeCallback();
return; return;
} }
if (output->non_desktop) {
Debug::log(LOG, "Not configuring non-desktop output");
if (g_pCompositor->m_sWRLDRMLeaseMgr) {
wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output);
}
return;
}
if (!m_bRenderingInitPassed) {
output->allocator = nullptr;
output->renderer = nullptr;
wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
m_bRenderingInitPassed = true;
}
if (!m_pThisWrap) {
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
m_pThisWrap = &m;
break;
}
}
}
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()){ if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()){
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap); g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
} }
m_bEnabled = true;
ID = g_pCompositor->getNextAvailableMonitorID(); m_bEnabled = true;
szName = output->name;
wlr_output_set_scale(output, monitorRule.scale); wlr_output_set_scale(output, monitorRule.scale);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale); wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, monitorRule.scale);
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: support other transforms
wlr_output_enable_adaptive_sync(output, 1);
// create it in the arr // create it in the arr
vecPosition = monitorRule.offset; vecPosition = monitorRule.offset;
vecSize = monitorRule.resolution; vecSize = monitorRule.resolution;
@@ -40,15 +99,11 @@ 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);
Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %x", output->name, (int)monitorRule.offset.x, (int)monitorRule.offset.y, (int)monitorRule.resolution.x, (int)monitorRule.resolution.y, output); Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %x", output->name, (int)vecPosition.x, (int)vecPosition.y, (int)vecPixelSize.x, (int)vecPixelSize.y, output);
damage = wlr_output_damage_create(output); damage = wlr_output_damage_create(output);
@@ -56,59 +111,37 @@ void CMonitor::onConnect(bool noRule) {
if (!pWLRWorkspaceGroupHandle) { if (!pWLRWorkspaceGroupHandle) {
pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr); pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
} }
wlr_ext_workspace_group_handle_v1_output_enter(pWLRWorkspaceGroupHandle, output); wlr_ext_workspace_group_handle_v1_output_enter(pWLRWorkspaceGroupHandle, output);
// Workspace setupDefaultWS(monitorRule);
std::string newDefaultWorkspaceName = "";
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace.c_str());
}
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this);
activeWorkspace = PNEWWORKSPACE->m_iID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
PNEWWORKSPACE->startAnim(true, true, true);
} else {
if (newDefaultWorkspaceName == "")
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();
// We are required to set the name here immediately
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
PNEWWORKSPACE->m_iID = WORKSPACEID;
}
activeWorkspace = PNEWWORKSPACE->m_iID;
scale = monitorRule.scale; scale = monitorRule.scale;
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering. m_pThisWrap = nullptr;
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle); forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
PNEWWORKSPACE->setActive(true);
// //
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->m_pLastMonitor = this; g_pCompositor->m_pLastMonitor = this;
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
g_pHyprRenderer->arrangeLayersForMonitor(ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
// ensure VRR (will enable if necessary)
g_pConfigManager->ensureVRR(this);
} }
void CMonitor::onDisconnect() { void CMonitor::onDisconnect() {
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
return;
// Cleanup everything. Move windows back, snap cursor, shit. // Cleanup everything. Move windows back, snap cursor, shit.
CMonitor* BACKUPMON = nullptr; CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
@@ -118,16 +151,39 @@ void CMonitor::onDisconnect() {
} }
} }
if (!BACKUPMON) { if (g_pCompositor->m_pLastMonitor == this)
Debug::log(CRIT, "No monitors! Unplugged last! Exiting."); g_pCompositor->m_pLastMonitor = BACKUPMON;
g_pCompositor->cleanup();
return; // remove mirror
if (pMirrorOf) {
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; }));
pMirrorOf = nullptr;
}
if (!mirrors.empty()) {
for (auto& m : mirrors) {
m->setMirror("");
}
g_pConfigManager->m_bWantsMonitorReload = true;
} }
m_bEnabled = false; m_bEnabled = false;
m_bRenderingInitPassed = false;
hyprListener_monitorFrame.removeCallback(); hyprListener_monitorFrame.removeCallback();
if (!BACKUPMON) {
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
hyprListener_monitorMode.removeCallback();
hyprListener_monitorDestroy.removeCallback();
g_pCompositor->m_bUnsafeState = true;
return;
}
const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName; const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;
// snap cursor // snap cursor
@@ -164,3 +220,144 @@ void CMonitor::onDisconnect() {
g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; })); g_pCompositor->m_vMonitors.erase(std::remove_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; }));
} }
void CMonitor::addDamage(pixman_region32_t* rg) {
wlr_output_damage_add(damage, rg);
}
void CMonitor::addDamage(wlr_box* box) {
wlr_output_damage_add_box(damage, box);
}
bool CMonitor::isMirror() {
return pMirrorOf != nullptr;
}
void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
// Workspace
std::string newDefaultWorkspaceName = "";
auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_vWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1;
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace.c_str());
}
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this);
activeWorkspace = PNEWWORKSPACE->m_iID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
PNEWWORKSPACE->startAnim(true, true, true);
} else {
if (newDefaultWorkspaceName == "")
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();
// We are required to set the name here immediately
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
PNEWWORKSPACE->m_iID = WORKSPACEID;
}
activeWorkspace = PNEWWORKSPACE->m_iID;
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
PNEWWORKSPACE->setActive(true);
}
void CMonitor::setMirror(const std::string& mirrorOf) {
const auto PMIRRORMON = g_pCompositor->getMonitorFromString(mirrorOf);
if (PMIRRORMON == pMirrorOf)
return;
if (PMIRRORMON && PMIRRORMON->isMirror()) {
Debug::log(ERR, "Cannot mirror a mirror!");
return;
}
if (PMIRRORMON == this) {
Debug::log(ERR, "Cannot mirror self!");
return;
}
if (!PMIRRORMON) {
// disable mirroring
if (pMirrorOf) {
pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; }));
}
pMirrorOf = nullptr;
// set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName, this->output->description ? this->output->description : "");
vecPosition = RULE.offset;
// push to mvmonitors
if (!m_pThisWrap) {
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
m_pThisWrap = &m;
break;
}
}
}
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()) {
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
}
setupDefaultWS(RULE);
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y);
} else {
CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m.get() != this) {
BACKUPMON = m.get();
break;
}
}
// move all the WS
std::deque<CWorkspace*> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID) {
wspToMove.push_back(w.get());
}
}
for (auto& w : wspToMove) {
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
w->startAnim(true, true, true);
}
activeWorkspace = -1;
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
vecPosition = Vector2D(-1337420, -1337420);
pMirrorOf = PMIRRORMON;
pMirrorOf->mirrors.push_back(this);
// remove from mvmonitors
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) != g_pCompositor->m_vMonitors.end()) {
g_pCompositor->m_vMonitors.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();
}
}

View File

@@ -7,9 +7,11 @@
#include <array> #include <array>
#include <memory> #include <memory>
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);
@@ -35,9 +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.
// mirroring
CMonitor* pMirrorOf = nullptr;
std::vector<CMonitor*> mirrors;
// for the special workspace // for the special workspace
bool specialWorkspaceOpen = false; bool specialWorkspaceOpen = false;
// 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
// and I am lazy // and I am lazy
@@ -55,13 +65,21 @@ public:
// methods // methods
void onConnect(bool noRule); void onConnect(bool noRule);
void onDisconnect(); void onDisconnect();
void addDamage(pixman_region32_t* rg);
void addDamage(wlr_box* box);
void setMirror(const std::string&);
bool isMirror();
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr; std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
// For the list lookup // For the list lookup
bool operator==(const CMonitor& rhs) { bool operator==(const CMonitor& rhs) {
return vecPosition == rhs.vecPosition && vecSize == rhs.vecSize && szName == rhs.szName; return vecPosition == rhs.vecPosition && vecSize == rhs.vecSize && szName == rhs.szName;
} }
};
private:
void setupDefaultWS(const SMonitorRule&);
};

View File

@@ -101,6 +101,14 @@ void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
g_pHyprRenderer->damageBox(&extents); g_pHyprRenderer->damageBox(&extents);
} }
// remove references to this node
for (auto& tn : surfaceTreeNodes) {
for (auto& cs : tn.childSubsurfaces) {
if (cs.pChild == pNode)
cs.pChild = nullptr;
}
}
surfaceTreeNodes.remove(*pNode); surfaceTreeNodes.remove(*pNode);
Debug::log(LOG, "SurfaceTree Node removed"); Debug::log(LOG, "SurfaceTree Node removed");
@@ -139,6 +147,9 @@ void Events::listener_newSubsurfaceNode(void* owner, void* data) {
PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner; PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner;
if (PSUBSURFACE->mapped)
listener_mapSubsurface(PNEWSUBSURFACE, nullptr);
wlr_subsurface* existingWlrSubsurface; wlr_subsurface* existingWlrSubsurface;
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) { wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) {
listener_newSubsurfaceNode(pNode, existingWlrSubsurface); listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
@@ -151,6 +162,9 @@ void Events::listener_newSubsurfaceNode(void* owner, void* data) {
void Events::listener_mapSubsurface(void* owner, void* data) { void Events::listener_mapSubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner; SSubsurface* subsurface = (SSubsurface*)owner;
if (subsurface->pChild)
return;
Debug::log(LOG, "Subsurface %x mapped", subsurface->pSubsurface); Debug::log(LOG, "Subsurface %x mapped", subsurface->pSubsurface);
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner); subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
@@ -164,21 +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 = {0}; if (IT != SubsurfaceTree::surfaceTreeNodes.end()) {
if (PNODE->pSurface) { int lx = 0, ly = 0;
wlr_surface_get_extends(PNODE->pSurface, &extents); addSurfaceGlobalOffset(PNODE, &lx, &ly);
extents.x += lx; wlr_box extents = {lx, ly, 0, 0};
extents.y += ly; if (PNODE->pSurface) {
extents.width = PNODE->pSurface->current.width;
extents.height = PNODE->pSurface->current.height;
g_pHyprRenderer->damageBox(&extents); g_pHyprRenderer->damageBox(&extents);
}
// SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
// subsurface->pChild = nullptr;
} }
SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
subsurface->pChild = nullptr;
} }
} }
@@ -187,7 +203,7 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
// no damaging if it's not visible // no damaging if it's not visible
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) { if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE) if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from %x because it's invisible.", pNode->pWindowOwner); Debug::log(LOG, "Refusing to commit damage from %x because it's invisible.", pNode->pWindowOwner);
return; return;
@@ -214,8 +230,9 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
void Events::listener_destroySubsurface(void* owner, void* data) { void Events::listener_destroySubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner; SSubsurface* subsurface = (SSubsurface*)owner;
if (subsurface->pChild) if (subsurface->pChild) {
listener_destroySubsurfaceNode(subsurface->pChild, nullptr); SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
}
Debug::log(LOG, "Subsurface %x destroyed", subsurface); Debug::log(LOG, "Subsurface %x destroyed", subsurface);

View File

@@ -35,6 +35,10 @@ class Vector2D {
return a.x != x || a.y != y; return a.x != x || a.y != y;
} }
Vector2D operator*(const Vector2D& a) const {
return Vector2D(this->x * a.x, this->y * a.y);
}
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()); Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D());
Vector2D floor(); Vector2D floor();

View File

@@ -73,6 +73,9 @@ struct SRenderData {
// only for windows, not popups // only for windows, not popups
bool squishOversized = true; bool squishOversized = true;
// for calculating UV
CWindow* pWindow = nullptr;
}; };
struct SExtensionFindingData { struct SExtensionFindingData {
@@ -94,11 +97,16 @@ struct SKeyboard {
DYNLISTENER(keyboardMod); DYNLISTENER(keyboardMod);
DYNLISTENER(keyboardKey); DYNLISTENER(keyboardKey);
DYNLISTENER(keyboardKeymap);
DYNLISTENER(keyboardDestroy); DYNLISTENER(keyboardDestroy);
bool isVirtual = false;
bool active = false; bool active = false;
xkb_layout_index_t activeLayout = 0;
std::string name = ""; std::string name = "";
std::string xkbFilePath = "";
SStringRuleNames currentRules; SStringRuleNames currentRules;
int repeatRate = 0; int repeatRate = 0;
@@ -123,6 +131,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);
@@ -185,7 +195,7 @@ struct SDrag {
bool iconMapped = false; bool iconMapped = false;
wlr_drag_icon* dragIcon = nullptr; wlr_drag_icon* dragIcon = nullptr;
Vector2D pos; Vector2D pos;
DYNLISTENER(destroyIcon); DYNLISTENER(destroyIcon);
@@ -272,4 +282,70 @@ struct SSwipeGesture {
int speedPoints = 0; int speedPoints = 0;
CMonitor* pMonitor = nullptr; CMonitor* pMonitor = nullptr;
}; };
struct STextInput {
wlr_text_input_v3* pWlrInput = nullptr;
wlr_surface* pPendingSurface = nullptr;
DYNLISTENER(textInputEnable);
DYNLISTENER(textInputDisable);
DYNLISTENER(textInputCommit);
DYNLISTENER(textInputDestroy);
DYNLISTENER(pendingSurfaceDestroy);
};
struct SIMEKbGrab {
wlr_input_method_keyboard_grab_v2* pWlrKbGrab = nullptr;
wlr_keyboard* pKeyboard = nullptr;
DYNLISTENER(grabDestroy);
};
struct SIMEPopup {
wlr_input_popup_surface_v2* pSurface = nullptr;
int x, y;
int realX, realY;
bool visible;
Vector2D lastSize;
DYNLISTENER(mapPopup);
DYNLISTENER(unmapPopup);
DYNLISTENER(destroyPopup);
DYNLISTENER(commitPopup);
DYNLISTENER(focusedSurfaceUnmap);
bool operator==(const SIMEPopup& other) {
return pSurface == other.pSurface;
}
};
struct STouchDevice {
wlr_input_device* pWlrDevice = nullptr;
std::string name = "";
std::string boundOutput = "";
DYNLISTENER(destroy);
bool operator==(const STouchDevice& other) {
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

@@ -12,7 +12,7 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
m_iMonitorID = monitorID; m_iMonitorID = monitorID;
m_szName = name; m_szName = name;
m_bIsSpecialWorkspace = special; m_bIsSpecialWorkspace = special;
if (!special) { if (!special) {
m_pWlrHandle = wlr_ext_workspace_handle_v1_create(PMONITOR->pWLRWorkspaceGroupHandle); m_pWlrHandle = wlr_ext_workspace_handle_v1_create(PMONITOR->pWLRWorkspaceGroupHandle);
@@ -26,9 +26,9 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
} }
m_vRenderOffset.m_pWorkspace = this; m_vRenderOffset.m_pWorkspace = this;
m_vRenderOffset.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE); m_vRenderOffset.create(AVARTYPE_VECTOR, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, AVARDAMAGE_ENTIRE);
m_fAlpha.m_pWorkspace = this; m_fAlpha.m_pWorkspace = this;
m_fAlpha.create(AVARTYPE_FLOAT, 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);
g_pEventManager->postEvent({"createworkspace", m_szName}, true); g_pEventManager->postEvent({"createworkspace", m_szName}, true);
@@ -91,6 +91,15 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
m_vRenderOffset.warp(); m_vRenderOffset.warp();
m_fAlpha.warp(); m_fAlpha.warp();
} }
// check LS-es
if (in) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
if (!ls->fadingOut)
ls->alpha = m_bHasFullscreenWindow && m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 255.f;
}
}
} }
void CWorkspace::setActive(bool on) { void CWorkspace::setActive(bool on) {
@@ -119,4 +128,11 @@ void CWorkspace::moveToMonitor(const int& id) {
wlr_ext_workspace_handle_v1_set_urgent(m_pWlrHandle, false); wlr_ext_workspace_handle_v1_set_urgent(m_pWlrHandle, false);
wlr_ext_workspace_handle_v1_set_name(m_pWlrHandle, m_szName.c_str()); wlr_ext_workspace_handle_v1_set_name(m_pWlrHandle, m_szName.c_str());
} }
CWindow* CWorkspace::getLastFocusedWindow() {
if (!g_pCompositor->windowValidMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow->m_iWorkspaceID != m_iID)
return nullptr;
return m_pLastFocusedWindow;
}

View File

@@ -8,6 +8,8 @@ enum eFullscreenMode : uint8_t {
FULLSCREEN_MAXIMIZED FULLSCREEN_MAXIMIZED
}; };
class CWindow;
class CWorkspace { class CWorkspace {
public: public:
CWorkspace(int monitorID, std::string name, bool special = false); CWorkspace(int monitorID, std::string name, bool special = false);
@@ -18,6 +20,9 @@ public:
int m_iID = -1; int m_iID = -1;
std::string m_szName = ""; std::string m_szName = "";
uint64_t m_iMonitorID = -1; uint64_t m_iMonitorID = -1;
// Previous workspace ID is stored during a workspace change, allowing travel
// to the previous workspace.
int m_iPrevWorkspaceID = -1;
bool m_bHasFullscreenWindow = false; bool m_bHasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL; eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL;
@@ -33,6 +38,9 @@ public:
// "scratchpad" // "scratchpad"
bool m_bIsSpecialWorkspace = false; bool m_bIsSpecialWorkspace = false;
// last window
CWindow* m_pLastFocusedWindow = nullptr;
// user-set // user-set
bool m_bDefaultFloating = false; bool m_bDefaultFloating = false;
bool m_bDefaultPseudo = false; bool m_bDefaultPseudo = false;
@@ -41,4 +49,6 @@ public:
void setActive(bool on); void setActive(bool on);
void moveToMonitor(const int&); void moveToMonitor(const int&);
CWindow* getLastFocusedWindow();
}; };

View File

@@ -0,0 +1,152 @@
#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
};
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) {}

View File

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

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
@@ -32,16 +31,20 @@
#define class _class #define class _class
#define namespace _namespace #define namespace _namespace
#define static #define static
#define delete delete_
extern "C" { extern "C" {
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/backend/libinput.h> #include <wlr/backend/libinput.h>
#include <wlr/backend/drm.h>
#include <wlr/render/allocator.h> #include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_data_control_v1.h> #include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_drm.h>
#include <wlr/types/wlr_export_dmabuf_v1.h> #include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h> #include <wlr/types/wlr_gamma_control_v1.h>
@@ -76,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>
@@ -94,8 +95,20 @@ extern "C" {
#include <wlr/types/wlr_xdg_foreign_v2.h> #include <wlr/types/wlr_xdg_foreign_v2.h>
#include <wlr/types/wlr_pointer_gestures_v1.h> #include <wlr/types/wlr_pointer_gestures_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h> #include <wlr/types/wlr_output_power_management_v1.h>
#include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_text_input_v3.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_switch.h>
#include <drm_fourcc.h>
#ifndef NO_XWAYLAND
#include <wlr/xwayland.h>
#include <X11/Xproto.h>
#endif
} }
#undef delete
#undef class #undef class
#undef namespace #undef namespace
#undef static #undef static
@@ -113,6 +126,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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -6,6 +6,16 @@ void IHyprLayout::onWindowCreated(CWindow* pWindow) {
if (pWindow->m_bIsFloating) { if (pWindow->m_bIsFloating) {
onWindowCreatedFloating(pWindow); onWindowCreatedFloating(pWindow);
} else { } else {
wlr_box desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f;
} else {
pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
}
onWindowCreatedTiling(pWindow); onWindowCreatedTiling(pWindow);
} }
} }
@@ -16,6 +26,9 @@ void IHyprLayout::onWindowRemoved(CWindow* pWindow) {
} else { } else {
onWindowRemovedTiling(pWindow); onWindowRemovedTiling(pWindow);
} }
if (pWindow == m_pLastTiledWindow)
m_pLastTiledWindow = nullptr;
} }
void IHyprLayout::onWindowRemovedFloating(CWindow* pWindow) { void IHyprLayout::onWindowRemovedFloating(CWindow* pWindow) {
@@ -36,11 +49,11 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(pWindow); const auto PWINDOWSURFACE = g_pXWaylandManager->getWindowSurface(pWindow);
pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height); pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height);
if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11) { // XDG windows should be fine. TODO: check for weird atoms? if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { // XDG windows should be fine. TODO: check for weird atoms?
pWindow->m_bHidden = true; pWindow->setHidden(true);
return; return;
} }
// reject any windows with size <= 5x5 // reject any windows with size <= 5x5
if (pWindow->m_vRealSize.goalv().x <= 5 || pWindow->m_vRealSize.goalv().y <= 5) { if (pWindow->m_vRealSize.goalv().x <= 5 || pWindow->m_vRealSize.goalv().y <= 5) {
pWindow->m_vRealSize = PMONITOR->vecSize / 2.f; pWindow->m_vRealSize = PMONITOR->vecSize / 2.f;
@@ -54,8 +67,24 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
// check if it's on the correct monitor! // check if it's on the correct monitor!
Vector2D middlePoint = Vector2D(desiredGeometry.x, desiredGeometry.y) + Vector2D(desiredGeometry.width, desiredGeometry.height) / 2.f; Vector2D middlePoint = Vector2D(desiredGeometry.x, desiredGeometry.y) + Vector2D(desiredGeometry.width, desiredGeometry.height) / 2.f;
// check if it's visible on any monitor (only for XDG)
bool visible = pWindow->m_bIsX11;
if (!pWindow->m_bIsX11) {
for (auto& m : g_pCompositor->m_vMonitors) {
if (VECINRECT(Vector2D(desiredGeometry.x, desiredGeometry.y), m->vecPosition.x, m->vecPosition.y, m->vecPosition.x + m->vecSize.x, m->vecPosition.y + m->vecPosition.y)
|| VECINRECT(Vector2D(desiredGeometry.x + desiredGeometry.width, desiredGeometry.y), m->vecPosition.x, m->vecPosition.y, m->vecPosition.x + m->vecSize.x, m->vecPosition.y + m->vecPosition.y)
|| VECINRECT(Vector2D(desiredGeometry.x, desiredGeometry.y + desiredGeometry.height), m->vecPosition.x, m->vecPosition.y, m->vecPosition.x + m->vecSize.x, m->vecPosition.y + m->vecPosition.y)
|| VECINRECT(Vector2D(desiredGeometry.x + desiredGeometry.width, desiredGeometry.y + desiredGeometry.height), m->vecPosition.x, m->vecPosition.y, m->vecPosition.x + m->vecSize.x, m->vecPosition.y + m->vecPosition.y)) {
visible = true;
break;
}
}
}
// TODO: detect a popup in a more consistent way. // TODO: detect a popup in a more consistent way.
if ((desiredGeometry.x == 0 && desiredGeometry.y == 0)) { if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible) {
// if it's not, fall back to the center placement // if it's not, fall back to the center placement
pWindow->m_vRealPosition = PMONITOR->vecPosition + Vector2D((PMONITOR->vecSize.x - desiredGeometry.width) / 2.f, (PMONITOR->vecSize.y - desiredGeometry.height) / 2.f); pWindow->m_vRealPosition = PMONITOR->vecPosition + Vector2D((PMONITOR->vecSize.x - desiredGeometry.width) / 2.f, (PMONITOR->vecSize.y - desiredGeometry.height) / 2.f);
} else { } else {
@@ -77,7 +106,6 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
if (pWindow->m_iX11Type != 2) { if (pWindow->m_iX11Type != 2) {
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
g_pCompositor->moveWindowToTop(pWindow); g_pCompositor->moveWindowToTop(pWindow);
} }
@@ -112,18 +140,35 @@ void IHyprLayout::onBeginDragWindow() {
DRAGGINGWINDOW->m_bDraggingTiled = false; DRAGGINGWINDOW->m_bDraggingTiled = false;
if (!DRAGGINGWINDOW->m_bIsFloating) { if (!DRAGGINGWINDOW->m_bIsFloating) {
if (g_pInputManager->dragButton == BTN_LEFT) { if (g_pInputManager->dragMode == MBIND_MOVE) {
changeWindowFloatingMode(DRAGGINGWINDOW); changeWindowFloatingMode(DRAGGINGWINDOW);
DRAGGINGWINDOW->m_bIsFloating = true; DRAGGINGWINDOW->m_bIsFloating = true;
DRAGGINGWINDOW->m_bDraggingTiled = true; DRAGGINGWINDOW->m_bDraggingTiled = true;
DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize.goalv() / 2.f;
} }
} }
m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal(); m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal();
m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.vec(); m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goalv();
m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.vec(); m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goalv();
m_vLastDragXY = m_vBeginDragXY; m_vLastDragXY = m_vBeginDragXY;
// get the grab corner
if (m_vBeginDragXY.x < m_vBeginDragPositionXY.x + m_vBeginDragSizeXY.x / 2.0) {
// left
if (m_vBeginDragXY.y < m_vBeginDragPositionXY.y + m_vBeginDragSizeXY.y / 2.0)
m_iGrabbedCorner = 0;
else
m_iGrabbedCorner = 4;
} else {
// right
if (m_vBeginDragXY.y < m_vBeginDragPositionXY.y + m_vBeginDragSizeXY.y / 2.0)
m_iGrabbedCorner = 1;
else
m_iGrabbedCorner = 3;
}
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
// shadow to ignore any bound to MAIN_MOD // shadow to ignore any bound to MAIN_MOD
@@ -156,6 +201,8 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y); const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y);
const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y); const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y);
const auto PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
if (abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) if (abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f)
return; return;
@@ -163,18 +210,47 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
if (g_pInputManager->dragButton == BTN_LEFT) { if (g_pInputManager->dragMode == MBIND_MOVE) {
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA);
DRAGGINGWINDOW->updateWindowDecos(); 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 { } else if (g_pInputManager->dragMode == MBIND_RESIZE) {
if (DRAGGINGWINDOW->m_bIsFloating) { if (DRAGGINGWINDOW->m_bIsFloating) {
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(m_vBeginDragSizeXY + DELTA);
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(Vector2D(std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().x, (double)20, (double)999999), std::clamp(DRAGGINGWINDOW->m_vRealSize.vec().y, (double)20, (double)999999)));
DRAGGINGWINDOW->updateWindowDecos(); const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW);
// calc the new size and pos
Vector2D newSize = m_vBeginDragSizeXY;
Vector2D newPos = m_vBeginDragPositionXY;
if (m_iGrabbedCorner == 3) {
newSize = newSize + DELTA;
} else if (m_iGrabbedCorner == 0) {
newSize = newSize - DELTA;
newPos = newPos + DELTA;
} else if (m_iGrabbedCorner == 1) {
newSize = newSize + Vector2D(DELTA.x, -DELTA.y);
newPos = newPos + Vector2D(0, DELTA.y);
} else if (m_iGrabbedCorner == 4) {
newSize = newSize + Vector2D(-DELTA.x, DELTA.y);
newPos = newPos + Vector2D(DELTA.x, 0);
}
newSize = newSize.clamp(Vector2D(20,20), MAXSIZE);
if (*PANIMATE) {
DRAGGINGWINDOW->m_vRealSize = newSize;
DRAGGINGWINDOW->m_vRealPosition = newPos;
} else {
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(newSize);
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(newPos);
}
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
} else { } else {
@@ -190,9 +266,13 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (PMONITOR) { if (PMONITOR) {
DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID; DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID;
DRAGGINGWINDOW->m_iWorkspaceID = PMONITOR->activeWorkspace; DRAGGINGWINDOW->moveToWorkspace(PMONITOR->activeWorkspace);
DRAGGINGWINDOW->updateToplevel();
} }
DRAGGINGWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
} }
@@ -206,12 +286,14 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
return; return;
} }
pWindow->m_bPinned = false;
const auto TILED = isWindowTiled(pWindow); const auto TILED = isWindowTiled(pWindow);
if (!TILED) { if (!TILED) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f); const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID; pWindow->m_iMonitorID = PNEWMON->ID;
pWindow->m_iWorkspaceID = PNEWMON->activeWorkspace; pWindow->moveToWorkspace(PNEWMON->activeWorkspace);
// save real pos cuz the func applies the default 5,5 mid // save real pos cuz the func applies the default 5,5 mid
const auto PSAVEDPOS = pWindow->m_vRealPosition.vec(); const auto PSAVEDPOS = pWindow->m_vRealPosition.vec();
@@ -220,6 +302,11 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
// if the window is pseudo, update its size // if the window is pseudo, update its size
pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec(); pWindow->m_vPseudoSize = pWindow->m_vRealSize.vec();
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
// 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);
@@ -227,6 +314,9 @@ 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));
if (pWindow == g_pCompositor->m_pLastWindow)
m_pLastTiledWindow = pWindow;
} else { } else {
pWindow->m_vSize = pWindow->m_vRealSize.vec(); pWindow->m_vSize = pWindow->m_vRealSize.vec();
pWindow->m_vPosition = pWindow->m_vRealPosition.vec(); pWindow->m_vPosition = pWindow->m_vRealPosition.vec();
@@ -235,17 +325,20 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
g_pCompositor->moveWindowToTop(pWindow); g_pCompositor->moveWindowToTop(pWindow);
const auto POS = pWindow->m_vRealPosition.goalv(); pWindow->m_vRealPosition = pWindow->m_vRealPosition.vec() + (pWindow->m_vRealSize.vec() - pWindow->m_vLastFloatingSize) / 2.f;
const auto SIZ = pWindow->m_vRealSize.goalv(); pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
pWindow->m_vRealPosition.setValueAndWarp(POS + Vector2D(5, 5));
pWindow->m_vRealSize.setValueAndWarp(SIZ - Vector2D(10, 10));
pWindow->m_vRealPosition = POS;
pWindow->m_vRealSize = SIZ;
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
pWindow->m_sSpecialRenderData.rounding = true;
if (pWindow == m_pLastTiledWindow)
m_pLastTiledWindow = nullptr;
} }
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
pWindow->updateToplevel();
} }
void IHyprLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) { void IHyprLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) {
@@ -262,4 +355,48 @@ void IHyprLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) {
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + delta; PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + delta;
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) {
// the window was floating, 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;
}

View File

@@ -79,7 +79,7 @@ public:
*/ */
virtual void onEndDragWindow(); virtual void onEndDragWindow();
/* /*
Called whenever the mouse moves, should the layout want to Called whenever the mouse moves, should the layout want to
do anything with it. do anything with it.
Useful for dragging. Useful for dragging.
*/ */
@@ -94,19 +94,19 @@ public:
/* /*
Called when a dispatcher requests a custom message Called when a dispatcher requests a custom message
The layout is free to ignore. The layout is free to ignore.
std::any is the reply. Can be empty. std::any is the reply. Can be empty.
*/ */
virtual std::any layoutMessage(SLayoutMessageHeader, std::string) = 0; virtual std::any layoutMessage(SLayoutMessageHeader, std::string) = 0;
/* /*
Required to be handled, but may return just SWindowRenderLayoutHints() Required to be handled, but may return just SWindowRenderLayoutHints()
Called when the renderer requests any special draw flags for Called when the renderer requests any special draw flags for
a specific window, e.g. border color for groups. a specific window, e.g. border color for groups.
*/ */
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*) = 0; virtual SWindowRenderLayoutHints requestRenderHints(CWindow*) = 0;
/* /*
Called when the user requests two windows to be swapped places. Called when the user requests two windows to be swapped places.
The layout is free to ignore. The layout is free to ignore.
*/ */
@@ -123,9 +123,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;
CWindow* m_pLastTiledWindow = nullptr;
};

View File

@@ -39,6 +39,8 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
static auto *const PNEWTOP = &g_pConfigManager->getConfigValuePtr("master:new_on_top")->intValue; static auto *const PNEWTOP = &g_pConfigManager->getConfigValuePtr("master:new_on_top")->intValue;
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back(); const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back();
PNODE->workspaceID = pWindow->m_iWorkspaceID; PNODE->workspaceID = pWindow->m_iWorkspaceID;
@@ -60,8 +62,33 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
PNODE->isMaster = true; PNODE->isMaster = true;
PNODE->percMaster = lastSplitPercent; PNODE->percMaster = lastSplitPercent;
// first, check if it isn't too big.
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PMONITOR->vecSize.x * lastSplitPercent || MAXSIZE.y < PMONITOR->vecSize.y) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
m_lMasterNodesData.remove(*PNODE);
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(pWindow);
return;
}
} else { } else {
PNODE->isMaster = false; PNODE->isMaster = false;
// first, check if it isn't too big.
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PMONITOR->vecSize.x * (1 - lastSplitPercent) || MAXSIZE.y < PMONITOR->vecSize.y * (1.f / (WINDOWSONWORKSPACE - 1))) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
m_lMasterNodesData.remove(*PNODE);
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(pWindow);
return;
}
}
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
} }
// recalc // recalc
@@ -74,6 +101,9 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
if (!PNODE) if (!PNODE)
return; return;
if (pWindow->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
if (PNODE->isMaster) { if (PNODE->isMaster) {
// find new one // find new one
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
@@ -103,7 +133,7 @@ void CHyprMasterLayout::recalculateMonitor(const int& monid) {
} }
if (PWORKSPACE->m_bHasFullscreenWindow) { if (PWORKSPACE->m_bHasFullscreenWindow) {
if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL)
return; return;
// massive hack from the fullscreen func // massive hack from the fullscreen func
@@ -195,9 +225,9 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y); const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y); const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); const auto PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
const auto GAPSIN = g_pConfigManager->getInt("general:gaps_in"); const auto PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
const auto GAPSOUT = g_pConfigManager->getInt("general:gaps_out"); const auto PGAPSOUT = &g_pConfigManager->getConfigValuePtr("general:gaps_out")->intValue;
const auto PWINDOW = pNode->pWindow; const auto PWINDOW = pNode->pWindow;
@@ -211,27 +241,31 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->m_vSize = pNode->size; PWINDOW->m_vSize = pNode->size;
PWINDOW->m_vPosition = pNode->position; PWINDOW->m_vPosition = pNode->position;
auto calcPos = PWINDOW->m_vPosition + Vector2D(BORDERSIZE, BORDERSIZE); auto calcPos = PWINDOW->m_vPosition + Vector2D(*PBORDERSIZE, *PBORDERSIZE);
auto calcSize = PWINDOW->m_vSize - Vector2D(2 * BORDERSIZE, 2 * BORDERSIZE); 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 && PWINDOW->m_iWorkspaceID != SPECIAL_WORKSPACE_ID && getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1) {
PWINDOW->m_vRealPosition = calcPos; PWINDOW->m_vRealPosition = calcPos - Vector2D(*PBORDERSIZE, *PBORDERSIZE);
PWINDOW->m_vRealSize = calcSize; PWINDOW->m_vRealSize = calcSize + Vector2D(2 * *PBORDERSIZE, 2 * *PBORDERSIZE);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
PWINDOW->m_sSpecialRenderData.rounding = false; PWINDOW->m_sSpecialRenderData.rounding = false;
PWINDOW->m_sSpecialRenderData.border = false;
PWINDOW->m_sSpecialRenderData.decorate = false;
return; return;
} }
PWINDOW->m_sSpecialRenderData.rounding = true; PWINDOW->m_sSpecialRenderData.rounding = true;
PWINDOW->m_sSpecialRenderData.border = true;
PWINDOW->m_sSpecialRenderData.decorate = true;
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? GAPSOUT : GAPSIN, const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? *PGAPSOUT : *PGAPSIN,
DISPLAYTOP ? GAPSOUT : GAPSIN); DISPLAYTOP ? *PGAPSOUT : *PGAPSIN);
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? GAPSOUT : GAPSIN, const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? *PGAPSOUT : *PGAPSIN,
DISPLAYBOTTOM ? GAPSOUT : GAPSIN); DISPLAYBOTTOM ? *PGAPSOUT : *PGAPSIN);
calcPos = calcPos + OFFSETTOPLEFT; calcPos = calcPos + OFFSETTOPLEFT;
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT; calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
@@ -250,6 +284,15 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize); g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
} }
if (m_bForceWarps) {
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealSize.warp();
g_pHyprRenderer->damageWindow(PWINDOW);
}
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
} }
@@ -266,7 +309,7 @@ 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::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).x, (double)20, (double)999999), std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).y, (double)20, (double)999999)); 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;
} }
@@ -278,6 +321,8 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2) if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) < 2)
return; return;
m_bForceWarps = true;
float delta = pixResize.x / PMONITOR->vecSize.x; float delta = pixResize.x / PMONITOR->vecSize.x;
PMASTER->percMaster += delta; PMASTER->percMaster += delta;
@@ -285,13 +330,15 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* p
std::clamp(PMASTER->percMaster, 0.05f, 0.95f); std::clamp(PMASTER->percMaster, 0.05f, 0.95f);
recalculateMonitor(PMONITOR->ID); recalculateMonitor(PMONITOR->ID);
m_bForceWarps = false;
} }
void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) { void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) {
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return; return;
if (on == pWindow->m_bIsFullscreen) if (on == pWindow->m_bIsFullscreen || pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
return; // ignore return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -357,10 +404,6 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
g_pCompositor->moveWindowToTop(pWindow); g_pCompositor->moveWindowToTop(pWindow);
// we need to fix XWayland windows by sending them to NARNIA
// because otherwise they'd still be recieving mouse events
g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
recalculateMonitor(PMONITOR->ID); recalculateMonitor(PMONITOR->ID);
} }
@@ -391,16 +434,17 @@ void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
return; return;
if (PNODE->workspaceID != PNODE2->workspaceID) { if (PNODE->workspaceID != PNODE2->workspaceID) {
Debug::log(ERR, "Master: Rejecting a swap between workspaces"); std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID);
return; std::swap(pWindow2->m_iWorkspaceID, pWindow->m_iWorkspaceID);
} }
// massive hack: just swap window pointers, lol // massive hack: just swap window pointers, lol
const auto PWINDOW1 = PNODE->pWindow; PNODE->pWindow = pWindow2;
PNODE->pWindow = PNODE2->pWindow; PNODE2->pWindow = pWindow;
PNODE2->pWindow = PWINDOW1;
recalculateMonitor(PWINDOW1->m_iMonitorID); recalculateMonitor(pWindow->m_iMonitorID);
if (PNODE2->workspaceID != PNODE->workspaceID)
recalculateMonitor(pWindow2->m_iMonitorID);
} }
void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) { void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
@@ -418,8 +462,80 @@ void CHyprMasterLayout::alterSplitRatioBy(CWindow* pWindow, float ratio) {
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->m_iMonitorID);
} }
CWindow* CHyprMasterLayout::getNextWindow(CWindow* pWindow, bool next) {
if (!isWindowTiled(pWindow))
return nullptr;
const auto PNODE = getNodeFromWindow(pWindow);
if (next) {
if (PNODE->isMaster) {
// focus the first non master
for (auto n : m_lMasterNodesData) {
if (n.pWindow != pWindow && n.workspaceID == pWindow->m_iWorkspaceID) {
return n.pWindow;
}
}
} else {
// focus next
bool reached = false;
bool found = false;
for (auto n : m_lMasterNodesData) {
if (n.pWindow == pWindow) {
reached = true;
continue;
}
if (n.workspaceID == pWindow->m_iWorkspaceID && reached) {
return n.pWindow;
}
}
if (!found) {
const auto PMASTER = getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID);
if (PMASTER)
return PMASTER->pWindow;
}
}
} else {
if (PNODE->isMaster) {
// focus the first non master
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->pWindow != pWindow && it->workspaceID == pWindow->m_iWorkspaceID) {
return it->pWindow;
}
}
} else {
// focus next
bool reached = false;
bool found = false;
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->pWindow == pWindow) {
reached = true;
continue;
}
if (it->workspaceID == pWindow->m_iWorkspaceID && reached) {
return it->pWindow;
}
}
if (!found) {
const auto PMASTER = getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID);
if (PMASTER)
return PMASTER->pWindow;
}
}
}
return nullptr;
}
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))
return;
g_pCompositor->focusWindow(PWINDOWTOCHANGETO); g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f; Vector2D middle = PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f;
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y); wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y);
@@ -445,80 +561,40 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
} else if (message == "cyclenext") { } else if (message == "cyclenext") {
const auto PWINDOW = header.pWindow; const auto PWINDOW = header.pWindow;
if (!isWindowTiled(PWINDOW)) switchToWindow(getNextWindow(PWINDOW, true));
return 0;
const auto PNODE = getNodeFromWindow(PWINDOW);
if (PNODE->isMaster) {
// focus the first non master
for (auto n : m_lMasterNodesData) {
if (n.pWindow != PWINDOW && n.workspaceID == PWINDOW->m_iWorkspaceID) {
switchToWindow(n.pWindow);
break;
}
}
} else {
// focus next
bool reached = false;
bool found = false;
for (auto n : m_lMasterNodesData) {
if (n.pWindow == PWINDOW) {
reached = true;
continue;
}
if (n.workspaceID == PWINDOW->m_iWorkspaceID && reached) {
switchToWindow(n.pWindow);
found = true;
break;
}
}
if (!found) {
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
if (PMASTER)
switchToWindow(PMASTER->pWindow);
}
}
} else if (message == "cycleprev") { } else if (message == "cycleprev") {
const auto PWINDOW = header.pWindow; const auto PWINDOW = header.pWindow;
if (!isWindowTiled(PWINDOW)) switchToWindow(getNextWindow(PWINDOW, false));
} else if (message == "swapnext") {
if (!g_pCompositor->windowValidMapped(header.pWindow))
return 0; return 0;
const auto PNODE = getNodeFromWindow(PWINDOW); if (header.pWindow->m_bIsFloating) {
g_pKeybindManager->m_mDispatchers["swapnext"]("");
return 0;
}
if (PNODE->isMaster) { const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true);
// focus the first non master
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->pWindow != PWINDOW && it->workspaceID == PWINDOW->m_iWorkspaceID) {
switchToWindow(it->pWindow);
break;
}
}
} else {
// focus next
bool reached = false;
bool found = false;
for (auto it = m_lMasterNodesData.rbegin(); it != m_lMasterNodesData.rend(); it++) {
if (it->pWindow == PWINDOW) {
reached = true;
continue;
}
if (it->workspaceID == PWINDOW->m_iWorkspaceID && reached) { if (PWINDOWTOSWAPWITH) {
switchToWindow(it->pWindow); switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
found = true; g_pCompositor->focusWindow(header.pWindow);
break; }
} } else if (message == "swapprev") {
} if (!g_pCompositor->windowValidMapped(header.pWindow))
if (!found) { return 0;
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
if (PMASTER) if (header.pWindow->m_bIsFloating) {
switchToWindow(PMASTER->pWindow); g_pKeybindManager->m_mDispatchers["swapnext"]("prev");
} return 0;
}
const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false);
if (PWINDOWTOSWAPWITH) {
switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
g_pCompositor->focusWindow(header.pWindow);
} }
} }
@@ -527,7 +603,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());
@@ -536,4 +612,4 @@ void CHyprMasterLayout::onEnable() {
void CHyprMasterLayout::onDisable() { void CHyprMasterLayout::onDisable() {
m_lMasterNodesData.clear(); m_lMasterNodesData.clear();
} }

View File

@@ -44,11 +44,14 @@ private:
std::list<SMasterNodeData> m_lMasterNodesData; std::list<SMasterNodeData> m_lMasterNodesData;
bool m_bForceWarps = false;
int getNodesOnWorkspace(const int&); int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SMasterNodeData*); void applyNodeDataToWindow(SMasterNodeData*);
SMasterNodeData* getNodeFromWindow(CWindow*); SMasterNodeData* getNodeFromWindow(CWindow*);
SMasterNodeData* getMasterNodeOnWorkspace(const int&); SMasterNodeData* getMasterNodeOnWorkspace(const int&);
void calculateWorkspace(const int&); void calculateWorkspace(const int&);
CWindow* getNextWindow(CWindow*, bool);
friend struct SMasterNodeData; friend struct SMasterNodeData;
}; };

View File

@@ -14,6 +14,12 @@ int main(int argc, char** argv) {
if (!getenv("XDG_RUNTIME_DIR")) if (!getenv("XDG_RUNTIME_DIR"))
throw std::runtime_error("XDG_RUNTIME_DIR is not set!"); throw std::runtime_error("XDG_RUNTIME_DIR is not set!");
// export HYPRLAND_CMD
std::string cmd = "";
for (auto i = 0; i < argc; ++i)
cmd += std::string(i == 0 ? "" : " ") + argv[i];
setenv("HYPRLAND_CMD", cmd.c_str(), 1);
// parse some args // parse some args
std::string configPath; std::string configPath;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
@@ -44,9 +50,13 @@ int main(int argc, char** argv) {
std::cout << "Welcome to Hyprland!\n"; std::cout << "Welcome to Hyprland!\n";
const auto LOGWLR = getenv("HYPRLAND_LOG_WLR");
if (LOGWLR && std::string(LOGWLR) == "1")
wlr_log_init(WLR_DEBUG, Debug::wlrLog);
// let's init the compositor. // let's init the compositor.
// it initializes basic Wayland stuff in the constructor. // it initializes basic Wayland stuff in the constructor.
g_pCompositor = std::make_unique<CCompositor>(); g_pCompositor = std::make_unique<CCompositor>();
g_pCompositor->explicitConfigPath = configPath; g_pCompositor->explicitConfigPath = configPath;
Debug::log(LOG, "Hyprland init finished."); Debug::log(LOG, "Hyprland init finished.");
@@ -57,7 +67,13 @@ int main(int argc, char** argv) {
// If we are here it means we got yote. // If we are here it means we got yote.
Debug::log(LOG, "Hyprland reached the end."); Debug::log(LOG, "Hyprland reached the end.");
g_pCompositor->cleanup(); wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
// kill all clients
for (auto& c : g_pCompositor->m_dProcessPIDsOnShutdown)
kill(c, SIGKILL);
wl_display_destroy(g_pCompositor->m_sWLDisplay);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -21,12 +21,12 @@ 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;
@@ -56,11 +56,13 @@ void CAnimationManager::tick() {
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};
@@ -147,11 +149,11 @@ void CAnimationManager::tick() {
g_pHyprRenderer->damageBox(&WLRBOXPREV); g_pHyprRenderer->damageBox(&WLRBOXPREV);
if (PWINDOW) { if (PWINDOW) {
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW);
} else if (PWORKSPACE) { } else if (PWORKSPACE) {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_bHidden) if (!w->m_bIsMapped || w->isHidden())
continue; continue;
if (w->m_iWorkspaceID != PWORKSPACE->m_iID) if (w->m_iWorkspaceID != PWORKSPACE->m_iID)
@@ -167,7 +169,7 @@ void CAnimationManager::tick() {
} }
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.
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
const auto ROUNDINGSIZE = *PROUNDING + 1; const auto ROUNDINGSIZE = *PROUNDING + 1;
@@ -190,14 +192,14 @@ void CAnimationManager::tick() {
} case AVARDAMAGE_SHADOW: { } case AVARDAMAGE_SHADOW: {
RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!"); RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!");
static auto* const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue; static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW);
if (PDECO) { if (PDECO) {
const auto EXTENTS = PDECO->getWindowDecorationExtents(); const auto EXTENTS = PDECO->getWindowDecorationExtents();
wlr_box dmg = {PWINDOW->m_vRealPosition.vec().x + EXTENTS.topLeft.x, PWINDOW->m_vRealPosition.vec().y + EXTENTS.topLeft.y, wlr_box dmg = {PWINDOW->m_vRealPosition.vec().x - EXTENTS.topLeft.x, PWINDOW->m_vRealPosition.vec().y - EXTENTS.topLeft.y,
PWINDOW->m_vRealSize.vec().x + EXTENTS.topLeft.x + EXTENTS.bottomRight.x, PWINDOW->m_vRealSize.vec().y + EXTENTS.topLeft.y + EXTENTS.bottomRight.y}; PWINDOW->m_vRealSize.vec().x + EXTENTS.topLeft.x + EXTENTS.bottomRight.x, PWINDOW->m_vRealSize.vec().y + EXTENTS.topLeft.y + EXTENTS.bottomRight.y};
if (!*PSHADOWIGNOREWINDOW) { if (!*PSHADOWIGNOREWINDOW) {
@@ -222,7 +224,7 @@ void CAnimationManager::tick() {
break; break;
} }
} }
// 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)
@@ -257,21 +259,30 @@ bool CAnimationManager::deltazero(const CColor& a, const CColor& b) {
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
} }
bool CAnimationManager::bezierExists(const std::string& bezier) {
for (auto&[bc, bz] : m_mBezierCurves) {
if (bc == bezier)
return true;
}
return false;
}
// //
// Anims // Anims
// //
// //
void CAnimationManager::animationPopin(CWindow* pWindow, bool close) { void CAnimationManager::animationPopin(CWindow* pWindow, bool close, float minPerc) {
const auto GOALPOS = pWindow->m_vRealPosition.goalv(); const auto GOALPOS = pWindow->m_vRealPosition.goalv();
const auto GOALSIZE = pWindow->m_vRealSize.goalv(); const auto GOALSIZE = pWindow->m_vRealSize.goalv();
if (!close) { if (!close) {
pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f); pWindow->m_vRealSize.setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}));
pWindow->m_vRealSize.setValue(Vector2D(5, 5)); pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_vValue / 2.f);
} else { } else {
pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f; pWindow->m_vRealSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y});
pWindow->m_vRealSize = Vector2D(5, 5); pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_vGoal / 2.f;
} }
} }
@@ -350,6 +361,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) {
@@ -361,14 +376,72 @@ void CAnimationManager::onWindowPostCreateClose(CWindow* pWindow, bool close) {
} }
} else { } else {
// anim popin, fallback // anim popin, fallback
animationPopin(pWindow, close);
float minPerc = 0.f;
if (pWindow->m_sAdditionalConfigData.animationStyle.find("%") != std::string::npos) {
try {
auto percstr = pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) {
; // oops
}
}
animationPopin(pWindow, close, minPerc / 100.f);
} }
} else { } else {
if (ANIMSTYLE == "slide") { if (ANIMSTYLE == "slide") {
animationSlide(pWindow, "", close); animationSlide(pWindow, "", close);
} else { } else {
// anim popin, fallback // anim popin, fallback
animationPopin(pWindow, close);
float minPerc = 0.f;
if (ANIMSTYLE.find("%") != 0) {
try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) {
; // oops
}
}
animationPopin(pWindow, close, minPerc / 100.f);
} }
} }
} }
std::string CAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) {
if (config.find("window") == 0) {
if (style == "slide") {
return "";
} else if (style.find("popin") == 0) {
// try parsing
float minPerc = 0.f;
if (style.find("%") != std::string::npos) {
try {
auto percstr = style.substr(style.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) {
return "invalid minperc";
}
return "";
}
minPerc; // fix warning
return "";
}
return "unknown style";
} else if (config == "workspaces" || config == "specialWorkspace") {
if (style == "slide" || style == "slidevert" || style == "fade")
return "";
return "unknown style";
} else {
return "animation has no styles";
}
return "";
}

View File

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

View File

@@ -18,8 +18,25 @@
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() {
std::thread([&]() { m_tThread = std::thread([&]() {
const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0); const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
if (SOCKET < 0) { if (SOCKET < 0) {
@@ -36,78 +53,75 @@ void CEventManager::startThread() {
// 10 max queued. // 10 max queued.
listen(SOCKET, 10); listen(SOCKET, 10);
char readBuf[1024] = {0};
sockaddr_in clientAddress; sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress); socklen_t clientSize = sizeof(clientAddress);
Debug::log(LOG, "Hypr socket 2 started at %s", socketPath.c_str()); Debug::log(LOG, "Hypr socket 2 started at %s", socketPath.c_str());
// set the socket nonblock
int flags = fcntl(SOCKET, F_GETFL, 0);
fcntl(SOCKET, F_SETFL, flags | O_NONBLOCK);
while (1) { while (1) {
const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize); const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize);
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);
// 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)});
} }
// pong if all FDs valid ensureFDsValid();
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);
}
// valid FDs, check the queue
// don't do anything if main thread is writing to the eventqueue
eventQueueMutex.lock();
if (m_dQueuedEvents.empty()){ // if queue empty, sleep and ignore
std::this_thread::sleep_for(std::chrono::milliseconds(1));
eventQueueMutex.unlock();
continue;
}
// write all queued events
for (auto& ev : m_dQueuedEvents) {
std::string eventString = (ev.event + ">>" + ev.data).substr(0, 1022) + "\n";
for (auto& fd : m_dAcceptedSocketFDs) {
write(fd, eventString.c_str(), eventString.length());
}
}
m_dQueuedEvents.clear();
eventQueueMutex.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} }
close(SOCKET); close(SOCKET);
}).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->first, &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() {
ensureFDsValid();
eventQueueMutex.lock();
for (auto& ev : m_dQueuedEvents) {
std::string eventString = (ev.event + ">>" + ev.data).substr(0, 1022) + "\n";
for (auto& fd : m_dAcceptedSocketFDs) {
write(fd.first, eventString.c_str(), eventString.length());
}
}
m_dQueuedEvents.clear();
eventQueueMutex.unlock();
} }
void CEventManager::postEvent(const SHyprIPCEvent event, bool force) { void CEventManager::postEvent(const SHyprIPCEvent event, bool force) {
if (m_bIgnoreEvents && !force) { if ((m_bIgnoreEvents && !force) || g_pCompositor->m_bIsShuttingDown) {
Debug::log(WARN, "Suppressed (ignoreevents true) event of type %s, content: %s",event.event.c_str(), event.data.c_str()); Debug::log(WARN, "Suppressed (ignoreevents true / shutting down) event of type %s, content: %s",event.event.c_str(), event.data.c_str());
return; return;
} }
@@ -115,5 +129,7 @@ void CEventManager::postEvent(const SHyprIPCEvent event, bool force) {
eventQueueMutex.lock(); eventQueueMutex.lock();
m_dQueuedEvents.push_back(ev); m_dQueuedEvents.push_back(ev);
eventQueueMutex.unlock(); eventQueueMutex.unlock();
flushEvents();
}, event).detach(); }, event).detach();
} }

View File

@@ -21,12 +21,17 @@ public:
bool m_bIgnoreEvents = false; bool m_bIgnoreEvents = false;
std::thread m_tThread;
private: private:
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;

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,7 @@ struct SKeybind {
std::string submap = ""; std::string submap = "";
bool release = false; bool release = false;
bool repeat = false; bool repeat = false;
bool mouse = false;
// DO NOT INITIALIZE // DO NOT INITIALIZE
bool shadowed = false; bool shadowed = false;
@@ -37,7 +38,8 @@ 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&);
uint32_t stringToModMask(std::string); uint32_t stringToModMask(std::string);
@@ -61,6 +63,11 @@ private:
uint32_t m_uTimeLastMs = 0; uint32_t m_uTimeLastMs = 0;
uint32_t m_uLastCode = 0; uint32_t m_uLastCode = 0;
uint32_t m_uLastMouseCode = 0;
bool m_bIsMouseBindActive = false;
int m_iPassPressed = -1; // used for pass
CTimer m_tScrollTimer; CTimer m_tScrollTimer;
@@ -69,8 +76,14 @@ private:
bool handleInternalKeybinds(xkb_keysym_t); bool handleInternalKeybinds(xkb_keysym_t);
bool handleVT(xkb_keysym_t); bool handleVT(xkb_keysym_t);
xkb_state* m_pXKBTranslationState = nullptr;
void updateXKBTranslationState();
bool ensureMouseBindState();
// -------------- Dispatchers -------------- // // -------------- Dispatchers -------------- //
static void killActive(std::string); static void killActive(std::string);
static void kill(std::string);
static void spawn(std::string); static void spawn(std::string);
static void toggleActiveFloating(std::string); static void toggleActiveFloating(std::string);
static void toggleActivePseudo(std::string); static void toggleActivePseudo(std::string);
@@ -94,6 +107,8 @@ private:
static void forceRendererReload(std::string); static void forceRendererReload(std::string);
static void resizeActive(std::string); static void resizeActive(std::string);
static void moveActive(std::string); static void moveActive(std::string);
static void moveWindow(std::string);
static void resizeWindow(std::string);
static void circleNext(std::string); static void circleNext(std::string);
static void focusWindow(std::string); static void focusWindow(std::string);
static void setSubmap(std::string); static void setSubmap(std::string);
@@ -101,6 +116,11 @@ private:
static void layoutmsg(std::string); static void layoutmsg(std::string);
static void toggleOpaque(std::string); static void toggleOpaque(std::string);
static void dpms(std::string); static void dpms(std::string);
static void swapnext(std::string);
static void swapActiveWorkspaces(std::string);
static void pinActive(std::string);
static void mouse(std::string);
static void bringActiveToTop(std::string);
friend class CCompositor; friend class CCompositor;
friend class CInputManager; friend class CInputManager;

View File

@@ -2,7 +2,7 @@
IHyprLayout* CLayoutManager::getCurrentLayout() { IHyprLayout* CLayoutManager::getCurrentLayout() {
switch (m_iCurrentLayoutID) { switch (m_iCurrentLayoutID) {
case DWINDLE: case DWINDLE:
return &m_cDwindleLayout; return &m_cDwindleLayout;
case MASTER: case MASTER:
return &m_cMasterLayout; return &m_cMasterLayout;
@@ -28,4 +28,4 @@ void CLayoutManager::switchToLayout(std::string layout) {
} else { } else {
Debug::log(ERR, "Unknown layout %s!", layout.c_str()); Debug::log(ERR, "Unknown layout %s!", layout.c_str());
} }
} }

View File

@@ -7,7 +7,10 @@ int slowUpdate = 0;
int handleTimer(void* data) { int handleTimer(void* data) {
const auto PTM = (CThreadManager*)data; const auto PTM = (CThreadManager*)data;
g_pConfigManager->tick(); static auto *const PDISABLECFGRELOAD = &g_pConfigManager->getConfigValuePtr("misc:disable_autoreload")->intValue;
if (*PDISABLECFGRELOAD != 1)
g_pConfigManager->tick();
wl_event_source_timer_update(PTM->m_esConfigTimer, 1000); wl_event_source_timer_update(PTM->m_esConfigTimer, 1000);
@@ -19,8 +22,6 @@ CThreadManager::CThreadManager() {
HyprCtl::startHyprCtlSocket(); HyprCtl::startHyprCtlSocket();
g_pCompositor->startHyprCtlTick();
m_esConfigTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleTimer, this); m_esConfigTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleTimer, this);
wl_event_source_timer_update(m_esConfigTimer, 1000); wl_event_source_timer_update(m_esConfigTimer, 1000);

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() {
@@ -32,38 +34,60 @@ wlr_surface* CHyprXWaylandManager::getWindowSurface(CWindow* pWindow) {
} }
void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) { void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) {
if (wlr_surface_is_xdg_surface(pSurface)) if (!pSurface)
wlr_xdg_toplevel_set_activated(wlr_xdg_surface_from_wlr_surface(pSurface)->toplevel, activate); return;
else if (wlr_surface_is_xwayland_surface(pSurface)) {
if (wlr_surface_is_xdg_surface(pSurface)) {
const auto PSURF = wlr_xdg_surface_from_wlr_surface(pSurface);
if (PSURF && PSURF->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
wlr_xdg_toplevel_set_activated(PSURF->toplevel, activate);
}
} else if (wlr_surface_is_xwayland_surface(pSurface)) {
wlr_xwayland_surface_activate(wlr_xwayland_surface_from_wlr_surface(pSurface), activate); wlr_xwayland_surface_activate(wlr_xwayland_surface_from_wlr_surface(pSurface), activate);
if (activate) if (activate)
wlr_xwayland_surface_restack(wlr_xwayland_surface_from_wlr_surface(pSurface), NULL, XCB_STACK_MODE_ABOVE); wlr_xwayland_surface_restack(wlr_xwayland_surface_from_wlr_surface(pSurface), NULL, XCB_STACK_MODE_ABOVE);
} }
} }
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)
wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false);
if (activate) {
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)
g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID)->m_pLastFocusedWindow = pWindow;
} }
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);
} }
@@ -120,9 +144,9 @@ void CHyprXWaylandManager::sendCloseWindow(CWindow* pWindow) {
} }
} }
void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, const Vector2D& size) { void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, const Vector2D& size, bool force) {
if ((pWindow->m_vReportedSize == size && pWindow->m_vRealPosition.vec() == pWindow->m_vReportedPosition) || (pWindow->m_vReportedSize == size && !pWindow->m_bIsX11)) if (!force && ((pWindow->m_vReportedSize == size && pWindow->m_vRealPosition.vec() == pWindow->m_vReportedPosition) || (pWindow->m_vReportedSize == size && !pWindow->m_bIsX11)))
return; return;
pWindow->m_vReportedPosition = pWindow->m_vRealPosition.vec(); pWindow->m_vReportedPosition = pWindow->m_vRealPosition.vec();
@@ -155,8 +179,11 @@ bool CHyprXWaylandManager::shouldBeFloated(CWindow* pWindow) {
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"]) pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
{ {
pWindow->m_bNoInitialFocus = true; if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
return true; pWindow->m_bX11ShouldntFocus = true;
pWindow->m_bNoInitialFocus = true;
return true;
} }
if (pWindow->m_uSurface.xwayland->role) { if (pWindow->m_uSurface.xwayland->role) {
@@ -184,7 +211,7 @@ bool CHyprXWaylandManager::shouldBeFloated(CWindow* pWindow) {
return true; return true;
} else { } else {
const auto PSTATE = &pWindow->m_uSurface.xdg->toplevel->current; const auto PSTATE = &pWindow->m_uSurface.xdg->toplevel->current;
if ((PSTATE->min_width != 0 && PSTATE->min_height != 0 && (PSTATE->min_width == PSTATE->max_width || PSTATE->min_height == PSTATE->max_height)) || pWindow->m_uSurface.xdg->toplevel->parent) if ((PSTATE->min_width != 0 && PSTATE->min_height != 0 && (PSTATE->min_width == PSTATE->max_width || PSTATE->min_height == PSTATE->max_height)) || pWindow->m_uSurface.xdg->toplevel->parent)
return true; return true;
} }
@@ -195,7 +222,7 @@ bool CHyprXWaylandManager::shouldBeFloated(CWindow* pWindow) {
void CHyprXWaylandManager::moveXWaylandWindow(CWindow* pWindow, const Vector2D& pos) { void CHyprXWaylandManager::moveXWaylandWindow(CWindow* pWindow, const Vector2D& pos) {
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return; return;
if (pWindow->m_bIsX11) { if (pWindow->m_bIsX11) {
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pos.x, pos.y, pWindow->m_vRealSize.vec().x, pWindow->m_vRealSize.vec().y); wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pos.x, pos.y, pWindow->m_vRealSize.vec().x, pWindow->m_vRealSize.vec().y);
} }
@@ -210,7 +237,7 @@ void CHyprXWaylandManager::checkBorders(CWindow* pWindow) {
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) { pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) {
pWindow->m_bX11DoesntWantBorders = true; pWindow->m_bX11DoesntWantBorders = true;
return; return;
} }
@@ -230,4 +257,22 @@ void CHyprXWaylandManager::setWindowFullscreen(CWindow* pWindow, bool fullscreen
if (pWindow->m_phForeignToplevel) if (pWindow->m_phForeignToplevel)
wlr_foreign_toplevel_handle_v1_set_fullscreen(pWindow->m_phForeignToplevel, fullscreen); wlr_foreign_toplevel_handle_v1_set_fullscreen(pWindow->m_phForeignToplevel, fullscreen);
} }
Vector2D CHyprXWaylandManager::getMaxSizeForWindow(CWindow* pWindow) {
if (!g_pCompositor->windowValidMapped(pWindow))
return Vector2D(99999, 99999);
if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel))
return Vector2D(99999, 99999);
auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height)
: Vector2D(pWindow->m_uSurface.xdg->toplevel->current.max_width, pWindow->m_uSurface.xdg->toplevel->current.max_height);
if (MAXSIZE.x < 5)
MAXSIZE.x = 99999;
if (MAXSIZE.y < 5)
MAXSIZE.y = 99999;
return MAXSIZE;
}

View File

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

View File

@@ -2,16 +2,18 @@
#include "../../Compositor.hpp" #include "../../Compositor.hpp"
void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) { void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) {
float sensitivity = g_pConfigManager->getFloat("general:sensitivity"); static auto *const PSENS = &g_pConfigManager->getConfigValuePtr("general:sensitivity")->floatValue;
static auto *const PNOACCEL = &g_pConfigManager->getConfigValuePtr("input:force_no_accel")->intValue;
static auto* const PSENSTORAW = &g_pConfigManager->getConfigValuePtr("general:apply_sens_to_raw")->intValue;
const auto DELTA = g_pConfigManager->getInt("input:force_no_accel") == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y); const auto DELTA = *PNOACCEL == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y);
if (g_pConfigManager->getInt("general:apply_sens_to_raw") == 1) if (*PSENSTORAW == 1)
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x * sensitivity, DELTA.y * sensitivity, e->unaccel_dx * sensitivity, e->unaccel_dy * sensitivity); wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x * *PSENS, DELTA.y * *PSENS, e->unaccel_dx * *PSENS, e->unaccel_dy * *PSENS);
else else
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x, DELTA.y, e->unaccel_dx, e->unaccel_dy); wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x, DELTA.y, e->unaccel_dx, e->unaccel_dy);
wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * sensitivity, DELTA.y * sensitivity); wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * *PSENS, DELTA.y * *PSENS);
mouseMoveUnified(e->time_msec); mouseMoveUnified(e->time_msec);
@@ -27,11 +29,17 @@ void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) {
} }
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue; static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
static auto* const PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue; static auto *const PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue;
static auto *const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
static auto *const PHOGFOCUS = &g_pConfigManager->getConfigValuePtr("misc:layers_hog_keyboard_focus")->intValue;
static auto *const PFLOATBEHAVIOR = &g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus")->intValue;
if (!g_pCompositor->m_bReadyToProcess) m_pFoundSurfaceToFocus = nullptr;
m_pFoundLSToFocus = nullptr;
m_pFoundWindowToFocus = nullptr;
if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown)
return; return;
if (!g_pCompositor->m_sSeat.mouse) { if (!g_pCompositor->m_sSeat.mouse) {
@@ -67,7 +75,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse); const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
if (!CONSTRAINTWINDOW) { if (!CONSTRAINTWINDOW) {
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr; unconstrainMouse();
} else { } else {
// Native Wayland apps know how 2 constrain themselves. // Native Wayland apps know how 2 constrain themselves.
// XWayland, we just have to accept them. Might cause issues, but thats XWayland for ya. // XWayland, we just have to accept them. Might cause issues, but thats XWayland for ya.
@@ -123,7 +131,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
ACTIVEWORKSPACE->setActive(true); ACTIVEWORKSPACE->setActive(true);
// event // event
g_pEventManager->postEvent(SHyprIPCEvent{"activemon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName}); g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", PMONITOR->szName + "," + ACTIVEWORKSPACE->m_szName});
} }
Vector2D surfaceCoords; Vector2D surfaceCoords;
@@ -135,34 +143,37 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
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);
if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface);
// then, we check if the workspace doesnt have a fullscreen window // then, we check if the workspace doesnt have a fullscreen window
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow);
surfacePos = pFoundWindow->m_vRealPosition.vec(); if (!pFoundWindow) {
// what the fuck, somehow happens occasionally??
PWORKSPACE->m_bHasFullscreenWindow = false;
return;
}
// 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_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)) || ((*w)->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && 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 (!foundSurface) if (!pFoundWindow->m_bIsX11) {
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface); 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) {
@@ -180,11 +191,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen)) if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen))
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
} }
} else } else {
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (!pFoundWindow && refocus) // TODO: this causes crashes, sometimes. ???
pFoundWindow = g_pCompositor->getFirstWindowOnWorkspace(PWORKSPACE->m_iID); // if (refocus && !pFoundWindow) {
// pFoundWindow = g_pCompositor->getFirstWindowOnWorkspace(PMONITOR->activeWorkspace);
// }
}
if (pFoundWindow) { if (pFoundWindow) {
if (!pFoundWindow->m_bIsX11) { if (!pFoundWindow->m_bIsX11) {
@@ -203,23 +217,30 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!foundSurface) if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface); foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface);
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor);
if (!foundSurface) { if (!foundSurface) {
if (m_ecbClickBehavior == CLICKMODE_KILL) if (!m_bEmptyFocusCursorSet) {
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor); // TODO: maybe wrap?
else if (m_ecbClickBehavior == CLICKMODE_KILL)
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor); wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "crosshair", g_pCompositor->m_sWLRCursor);
else
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
m_bEmptyFocusCursorSet = true;
}
wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat); wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat);
if (refocus) { // if we are forcing a refocus, and we don't find a surface, clear the kb focus too! if (refocus) { // if we are forcing a refocus, and we don't find a surface, clear the kb focus too!
g_pCompositor->focusSurface(nullptr); g_pCompositor->focusWindow(nullptr);
g_pCompositor->m_pLastWindow = nullptr;
} }
return; return;
} }
m_bEmptyFocusCursorSet = false;
if (time) if (time)
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);
@@ -233,30 +254,64 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
surfaceLocal = mouseCoords - surfacePos + Vector2D(geom.x, geom.y); surfaceLocal = mouseCoords - surfacePos + Vector2D(geom.x, geom.y);
} }
bool allowKeyboardRefocus = true;
if (*PHOGFOCUS && !refocus && g_pCompositor->m_pLastFocus) {
const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
if (PLS && PLS->layerSurface->current.keyboard_interactive) {
allowKeyboardRefocus = false;
}
}
// 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)) { 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) 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) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} }
if (pFoundWindow == g_pCompositor->m_pLastWindow && foundSurface != g_pCompositor->m_pLastFocus) { if (pFoundWindow == g_pCompositor->m_pLastWindow) {
// we changed the subsurface if (foundSurface != g_pCompositor->m_pLastFocus || m_bLastFocusOnLS) {
// ^^^ changed the subsurface ^^^ came back from a LS
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
}
if (*PFOLLOWONDND && m_sDrag.dragIcon) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} }
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); if (*PFOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow)
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
m_bLastFocusOnLS = false;
return; // don't enter any new surfaces return; // don't enter any new surfaces
} else { } else {
if (*PFOLLOWMOUSE != 3) if ((*PFOLLOWMOUSE != 3 && allowKeyboardRefocus) || refocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface); g_pCompositor->focusWindow(pFoundWindow, foundSurface);
} }
} else if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3)
g_pCompositor->focusSurface(foundSurface); m_bLastFocusOnLS = false;
} else {
if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3 && allowKeyboardRefocus) {
g_pCompositor->focusSurface(foundSurface);
}
if (pFoundLayerSurface)
m_bLastFocusOnLS = true;
}
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
@@ -315,7 +370,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
m_ecbClickBehavior = CLICKMODE_KILL; m_ecbClickBehavior = CLICKMODE_KILL;
// remove constraints // remove constraints
g_pCompositor->m_sSeat.mouse->constraintActive = false; g_pInputManager->unconstrainMouse();
refocus(); refocus();
// set cursor // set cursor
@@ -323,7 +378,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
break; break;
default: default:
break; break;
} }
} }
void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
@@ -347,25 +402,11 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
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);
if ((e->button == BTN_LEFT || e->button == BTN_RIGHT) && wlr_keyboard_get_modifiers(PKEYBOARD) == (uint32_t)g_pConfigManager->getInt("general:main_mod_internal")) {
currentlyDraggedWindow = g_pCompositor->windowFromCursor();
dragButton = e->button;
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
return;
}
break; break;
case WLR_BUTTON_RELEASED: case WLR_BUTTON_RELEASED:
if (currentlyDraggedWindow) {
g_pLayoutManager->getCurrentLayout()->onEndDragWindow();
currentlyDraggedWindow = nullptr;
dragButton = -1;
}
break; break;
} }
@@ -380,7 +421,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;
} }
@@ -400,12 +441,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);
} }
} }
@@ -428,10 +474,19 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard"); PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard"); PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard");
if (m_pActiveKeyboard) PNEWKEYBOARD->hyprListener_keyboardKeymap.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.keymap, [&](void* owner, void* data) {
m_pActiveKeyboard->active = false; const auto PKEYBOARD = (SKeyboard*)owner;
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", PKEYBOARD->name + "," +getActiveLayoutForKeyboard(PKEYBOARD)}, true); // force as this should ALWAYS be sent
}, PNEWKEYBOARD, "Keyboard");
disableAllKeyboards(false);
m_pActiveKeyboard = PNEWKEYBOARD; m_pActiveKeyboard = PNEWKEYBOARD;
PNEWKEYBOARD->active = true;
applyConfigToKeyboard(PNEWKEYBOARD); applyConfigToKeyboard(PNEWKEYBOARD);
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(keyboard)); wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(keyboard));
@@ -439,9 +494,46 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
Debug::log(LOG, "New keyboard created, pointers Hypr: %x and WLR: %x", PNEWKEYBOARD, keyboard); Debug::log(LOG, "New keyboard created, pointers Hypr: %x and WLR: %x", PNEWKEYBOARD, keyboard);
} }
void CInputManager::newVirtualKeyboard(wlr_input_device* keyboard) {
const auto PNEWKEYBOARD = &m_lKeyboards.emplace_back();
PNEWKEYBOARD->keyboard = keyboard;
PNEWKEYBOARD->isVirtual = true;
try {
PNEWKEYBOARD->name = std::string(keyboard->name);
} catch (std::exception& e) {
Debug::log(ERR, "Keyboard had no name???"); // logic error
}
PNEWKEYBOARD->hyprListener_keyboardMod.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.modifiers, &Events::listener_keyboardMod, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardKeymap.initCallback(&wlr_keyboard_from_input_device(keyboard)->events.keymap, [&](void* owner, void* data) {
const auto PKEYBOARD = (SKeyboard*)owner;
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", PKEYBOARD->name + "," +getActiveLayoutForKeyboard(PKEYBOARD)}, true); // force as this should ALWAYS be sent
}, PNEWKEYBOARD, "Keyboard");
disableAllKeyboards(true);
m_pActiveKeyboard = PNEWKEYBOARD;
PNEWKEYBOARD->active = true;
applyConfigToKeyboard(PNEWKEYBOARD);
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(keyboard));
Debug::log(LOG, "New virtual keyboard created, pointers Hypr: %x and WLR: %x", PNEWKEYBOARD, keyboard);
}
void CInputManager::setKeyboardLayout() { void CInputManager::setKeyboardLayout() {
for (auto& k : m_lKeyboards) for (auto& k : m_lKeyboards)
applyConfigToKeyboard(&k); applyConfigToKeyboard(&k);
g_pKeybindManager->updateXKBTranslationState();
} }
void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) { void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
@@ -462,6 +554,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
const auto NUMLOCKON = HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "numlock_by_default") : g_pConfigManager->getInt("input:numlock_by_default"); const auto NUMLOCKON = HASCONFIG ? g_pConfigManager->getDeviceInt(devname, "numlock_by_default") : g_pConfigManager->getInt("input:numlock_by_default");
const auto FILEPATH = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_file") : g_pConfigManager->getString("input:kb_file");
const auto RULES = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_rules") : g_pConfigManager->getString("input:kb_rules"); const auto RULES = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_rules") : g_pConfigManager->getString("input:kb_rules");
const auto MODEL = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_model") : g_pConfigManager->getString("input:kb_model"); const auto MODEL = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_model") : g_pConfigManager->getString("input:kb_model");
const auto LAYOUT = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_layout") : g_pConfigManager->getString("input:kb_layout"); const auto LAYOUT = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_layout") : g_pConfigManager->getString("input:kb_layout");
@@ -469,7 +562,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
const auto OPTIONS = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_options") : g_pConfigManager->getString("input:kb_options"); const auto OPTIONS = HASCONFIG ? g_pConfigManager->getDeviceString(devname, "kb_options") : g_pConfigManager->getString("input:kb_options");
try { try {
if (NUMLOCKON == pKeyboard->numlockOn && REPEATDELAY == pKeyboard->repeatDelay && REPEATRATE == pKeyboard->repeatRate && RULES != "" && RULES == pKeyboard->currentRules.rules && MODEL == pKeyboard->currentRules.model && LAYOUT == pKeyboard->currentRules.layout && VARIANT == pKeyboard->currentRules.variant && OPTIONS == pKeyboard->currentRules.options) { if (NUMLOCKON == pKeyboard->numlockOn && REPEATDELAY == pKeyboard->repeatDelay && REPEATRATE == pKeyboard->repeatRate && RULES != "" && RULES == pKeyboard->currentRules.rules && MODEL == pKeyboard->currentRules.model && LAYOUT == pKeyboard->currentRules.layout && VARIANT == pKeyboard->currentRules.variant && OPTIONS == pKeyboard->currentRules.options && FILEPATH == pKeyboard->xkbFilePath) {
Debug::log(LOG, "Not applying config to keyboard, it did not change."); Debug::log(LOG, "Not applying config to keyboard, it did not change.");
return; return;
} }
@@ -483,6 +576,7 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
pKeyboard->repeatDelay = REPEATDELAY; pKeyboard->repeatDelay = REPEATDELAY;
pKeyboard->repeatRate = REPEATRATE; pKeyboard->repeatRate = REPEATRATE;
pKeyboard->numlockOn = NUMLOCKON; pKeyboard->numlockOn = NUMLOCKON;
pKeyboard->xkbFilePath = FILEPATH.c_str();
xkb_rule_names rules = { xkb_rule_names rules = {
.rules = RULES.c_str(), .rules = RULES.c_str(),
@@ -506,9 +600,25 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
Debug::log(LOG, "Attempting to create a keymap for layout %s with variant %s (rules: %s, model: %s, options: %s)", rules.layout, rules.variant, rules.rules, rules.model, rules.options); Debug::log(LOG, "Attempting to create a keymap for layout %s with variant %s (rules: %s, model: %s, options: %s)", rules.layout, rules.variant, rules.rules, rules.model, rules.options);
auto KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); xkb_keymap * KEYMAP = NULL;
if (!FILEPATH.empty()) {
auto path = absolutePath(FILEPATH, g_pConfigManager->configCurrentPath);
if (!std::filesystem::exists(path)) {
Debug::log(ERR, "input:kb_file= file doesnt exist");
} else {
KEYMAP = xkb_keymap_new_from_file(CONTEXT, fopen(path.c_str(), "r"), XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
}
if (!KEYMAP) { if (!KEYMAP) {
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
if (!KEYMAP) {
g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS + ", layout: " + LAYOUT + " )");
Debug::log(ERR, "Keyboard layout %s with variant %s (rules: %s, model: %s, options: %s) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, rules.options); Debug::log(ERR, "Keyboard layout %s with variant %s (rules: %s, model: %s, options: %s) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, rules.options);
memset(&rules, 0, sizeof(rules)); memset(&rules, 0, sizeof(rules));
@@ -540,8 +650,10 @@ void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
xkb_keymap_unref(KEYMAP); xkb_keymap_unref(KEYMAP);
xkb_context_unref(CONTEXT); xkb_context_unref(CONTEXT);
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->name + "," +getActiveLayoutForKeyboard(pKeyboard)}, true); // force as this should ALWAYS be sent
Debug::log(LOG, "Set the keyboard layout to %s and variant to %s for keyboard \"%s\"", rules.layout, rules.variant, pKeyboard->keyboard->name); Debug::log(LOG, "Set the keyboard layout to %s and variant to %s for keyboard \"%s\"", rules.layout, rules.variant, pKeyboard->keyboard->name);
} }
void CInputManager::newMouse(wlr_input_device* mouse, bool virt) { void CInputManager::newMouse(wlr_input_device* mouse, bool virt) {
m_lMice.emplace_back(); m_lMice.emplace_back();
@@ -561,12 +673,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(); 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); wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, mouse);
PMOUSE->connected = true;
g_pCompositor->m_sSeat.mouse = PMOUSE; g_pCompositor->m_sSeat.mouse = PMOUSE;
m_tmrLastCursorMovement.reset(); m_tmrLastCursorMovement.reset();
@@ -574,15 +688,26 @@ 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); 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);
@@ -591,6 +716,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);
@@ -598,6 +728,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 == "" || SCROLLMETHOD == STRVAL_EMPTY) {
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
@@ -622,10 +767,20 @@ 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 == "" || ACCELPROFILE == STRVAL_EMPTY) {
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");
}
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);
} }
} }
@@ -661,7 +816,7 @@ void CInputManager::destroyMouse(wlr_input_device* mouse) {
g_pCompositor->m_sSeat.mouse = m_lMice.size() > 0 ? &m_lMice.front() : nullptr; g_pCompositor->m_sSeat.mouse = m_lMice.size() > 0 ? &m_lMice.front() : nullptr;
if (g_pCompositor->m_sSeat.mouse) if (g_pCompositor->m_sSeat.mouse)
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr; unconstrainMouse();
} }
void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) { void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
@@ -670,14 +825,42 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat); wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
if (passEvent) { if (passEvent) {
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e->time_msec, e->keycode, e->state); const auto PIMEGRAB = m_sIMERelay.getIMEKeyboardGrab(pKeyboard);
if (PIMEGRAB && PIMEGRAB->pWlrKbGrab && PIMEGRAB->pWlrKbGrab->input_method) {
wlr_input_method_keyboard_grab_v2_set_keyboard(PIMEGRAB->pWlrKbGrab, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_input_method_keyboard_grab_v2_send_key(PIMEGRAB->pWlrKbGrab, e->time_msec, e->keycode, e->state);
} else {
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e->time_msec, e->keycode, e->state);
}
} }
} }
void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) { void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard)); const auto PIMEGRAB = m_sIMERelay.getIMEKeyboardGrab(pKeyboard);
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers);
const auto ALLMODS = accumulateModsFromAllKBs();
auto MODS = wlr_keyboard_from_input_device(pKeyboard->keyboard)->modifiers;
MODS.depressed = ALLMODS;
if (PIMEGRAB && PIMEGRAB->pWlrKbGrab && PIMEGRAB->pWlrKbGrab->input_method) {
wlr_input_method_keyboard_grab_v2_set_keyboard(PIMEGRAB->pWlrKbGrab, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_input_method_keyboard_grab_v2_send_modifiers(PIMEGRAB->pWlrKbGrab, &MODS);
} else {
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, wlr_keyboard_from_input_device(pKeyboard->keyboard));
wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &MODS);
}
const auto PWLRKB = wlr_keyboard_from_input_device(pKeyboard->keyboard);
if (PWLRKB->modifiers.group != pKeyboard->activeLayout) {
pKeyboard->activeLayout = PWLRKB->modifiers.group;
g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->name + "," + getActiveLayoutForKeyboard(pKeyboard)}, true); // force as this should ALWAYS be sent
}
} }
void CInputManager::refocus() { void CInputManager::refocus() {
@@ -685,16 +868,16 @@ void CInputManager::refocus() {
} }
void CInputManager::updateDragIcon() { void CInputManager::updateDragIcon() {
if (!g_pInputManager->m_sDrag.dragIcon) if (!m_sDrag.dragIcon)
return; return;
switch (g_pInputManager->m_sDrag.dragIcon->drag->grab_type) { switch (m_sDrag.dragIcon->drag->grab_type) {
case WLR_DRAG_GRAB_KEYBOARD: case WLR_DRAG_GRAB_KEYBOARD:
break; break;
case WLR_DRAG_GRAB_KEYBOARD_POINTER: { case WLR_DRAG_GRAB_KEYBOARD_POINTER: {
wlr_box box = {g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4}; wlr_box box = {m_sDrag.pos.x - 2, m_sDrag.pos.y - 2, m_sDrag.dragIcon->surface->current.width + 4, m_sDrag.dragIcon->surface->current.height + 4};
g_pHyprRenderer->damageBox(&box); g_pHyprRenderer->damageBox(&box);
g_pInputManager->m_sDrag.pos = g_pInputManager->getMouseCoordsInternal(); m_sDrag.pos = getMouseCoordsInternal();
break; break;
} }
default: default:
@@ -750,7 +933,7 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
} }
} }
} }
wlr_pointer_constraint_v1_send_deactivated(pMouse->currentConstraint); wlr_pointer_constraint_v1_send_deactivated(pMouse->currentConstraint);
} }
@@ -773,6 +956,25 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
Debug::log(LOG, "Constrained mouse to %x", pMouse->currentConstraint); Debug::log(LOG, "Constrained mouse to %x", pMouse->currentConstraint);
} }
void CInputManager::unconstrainMouse() {
if (!g_pCompositor->m_sSeat.mouse->currentConstraint)
return;
const auto CONSTRAINTWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
if (CONSTRAINTWINDOW) {
g_pXWaylandManager->activateSurface(g_pXWaylandManager->getWindowSurface(CONSTRAINTWINDOW), false);
}
wlr_pointer_constraint_v1_send_deactivated(g_pCompositor->m_sSeat.mouse->currentConstraint);
g_pCompositor->m_sSeat.mouse->constraintActive = false;
// TODO: its better to somehow detect the workspace...
g_pCompositor->m_sSeat.mouse->currentConstraint = nullptr;
g_pCompositor->m_sSeat.mouse->hyprListener_commitConstraint.removeCallback();
}
void Events::listener_commitConstraint(void* owner, void* data) { void Events::listener_commitConstraint(void* owner, void* data) {
//g_pInputManager->recheckConstraint((SMouse*)owner); //g_pInputManager->recheckConstraint((SMouse*)owner);
} }
@@ -802,8 +1004,151 @@ 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)
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));
} }
return finalMask; return finalMask;
} }
std::string CInputManager::getActiveLayoutForKeyboard(SKeyboard* pKeyboard) {
const auto WLRKB = wlr_keyboard_from_input_device(pKeyboard->keyboard);
const auto KEYMAP = WLRKB->keymap;
const auto STATE = WLRKB->xkb_state;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE)) {
const auto LAYOUTNAME = xkb_keymap_layout_get_name(KEYMAP, i);
if (LAYOUTNAME)
return std::string(LAYOUTNAME);
return "error";
}
}
return "none";
}
void CInputManager::disableAllKeyboards(bool virt) {
for (auto& k : m_lKeyboards) {
if (k.isVirtual != virt)
continue;
k.active = false;
}
}
void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
const auto PNEWDEV = &m_lTouchDevices.emplace_back();
PNEWDEV->pWlrDevice = pDevice;
try {
PNEWDEV->name = std::string(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);
Debug::log(LOG, "New touch device added at %x", PNEWDEV);
PNEWDEV->hyprListener_destroy.initCallback(&pDevice->events.destroy, [&](void* owner, void* data) {
destroyTouchDevice((STouchDevice*)data);
}, 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;
auto devname = PTOUCHDEV->name;
transform(devname.begin(), devname.end(), devname.begin(), ::tolower);
const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname);
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(devname, "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(devname, "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) {
Debug::log(LOG, "Touch device at %x removed", 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);
}

View File

@@ -5,35 +5,57 @@
#include "../../helpers/WLClasses.hpp" #include "../../helpers/WLClasses.hpp"
#include "../../Window.hpp" #include "../../Window.hpp"
#include "../../helpers/Timer.hpp" #include "../../helpers/Timer.hpp"
#include "InputMethodRelay.hpp"
enum eClickBehaviorMode { enum eClickBehaviorMode {
CLICKMODE_DEFAULT = 0, CLICKMODE_DEFAULT = 0,
CLICKMODE_KILL CLICKMODE_KILL
}; };
enum eMouseBindMode {
MBIND_INVALID = -1,
MBIND_MOVE = 0,
MBIND_RESIZE
};
struct STouchData {
CWindow* touchFocusWindow = nullptr;
SLayerSurface* touchFocusLS = nullptr;
wlr_surface* touchFocusSurface = nullptr;
Vector2D touchSurfaceOrigin;
};
class CInputManager { class CInputManager {
public: public:
void onMouseMoved(wlr_pointer_motion_event*); void onMouseMoved(wlr_pointer_motion_event*);
void onMouseWarp(wlr_pointer_motion_absolute_event*); void onMouseWarp(wlr_pointer_motion_absolute_event*);
void onMouseButton(wlr_pointer_button_event*); void onMouseButton(wlr_pointer_button_event*);
void onMouseWheel(wlr_pointer_axis_event*); void onMouseWheel(wlr_pointer_axis_event*);
void onKeyboardKey(wlr_keyboard_key_event*, SKeyboard*); void onKeyboardKey(wlr_keyboard_key_event*, SKeyboard*);
void onKeyboardMod(void*, SKeyboard*); void onKeyboardMod(void*, SKeyboard*);
void newKeyboard(wlr_input_device*); void newKeyboard(wlr_input_device*);
void newVirtualKeyboard(wlr_input_device*);
void newMouse(wlr_input_device*, bool virt = false); void newMouse(wlr_input_device*, bool virt = false);
void newTouchDevice(wlr_input_device*);
void newSwitch(wlr_input_device*);
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();
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(wlr_input_device*);
@@ -42,10 +64,18 @@ public:
eClickBehaviorMode getClickMode(); eClickBehaviorMode getClickMode();
void processMouseRequest(wlr_seat_pointer_request_set_cursor_event*); void processMouseRequest(wlr_seat_pointer_request_set_cursor_event*);
void onTouchDown(wlr_touch_down_event*);
void onTouchUp(wlr_touch_up_event*);
void onTouchMove(wlr_touch_motion_event*);
void onPointerHoldBegin(wlr_pointer_hold_begin_event*);
void onPointerHoldEnd(wlr_pointer_hold_end_event*);
STouchData m_sTouchData;
// for dragging floating windows // for dragging floating windows
CWindow* currentlyDraggedWindow = nullptr; CWindow* currentlyDraggedWindow = nullptr;
int dragButton = -1; eMouseBindMode dragMode = MBIND_INVALID;
SDrag m_sDrag; SDrag m_sDrag;
@@ -61,6 +91,12 @@ public:
// idle inhibitors // idle inhibitors
std::list<SIdleInhibitor> m_lIdleInhibitors; std::list<SIdleInhibitor> m_lIdleInhibitors;
// Touch devices
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);
@@ -77,18 +113,28 @@ public:
CTimer m_tmrLastCursorMovement; CTimer m_tmrLastCursorMovement;
CInputMethodRelay m_sIMERelay;
// for shared mods // for shared mods
uint32_t accumulateModsFromAllKBs(); uint32_t accumulateModsFromAllKBs();
CWindow* m_pFollowOnDnDBegin = nullptr;
private: private:
// for click behavior override // for click behavior override
eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT; eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT;
bool m_bEmptyFocusCursorSet = false;
Vector2D m_vLastCursorPosFloored = Vector2D(); Vector2D m_vLastCursorPosFloored = Vector2D();
// for some bugs in follow mouse 0
bool m_bLastFocusOnLS = false;
void processMouseDownNormal(wlr_pointer_button_event* e); void processMouseDownNormal(wlr_pointer_button_event* e);
void processMouseDownKill(wlr_pointer_button_event* e); void processMouseDownKill(wlr_pointer_button_event* e);
void disableAllKeyboards(bool virt = false);
uint32_t m_uiCapabilities = 0; uint32_t m_uiCapabilities = 0;
void mouseMoveUnified(uint32_t, bool refocus = false); void mouseMoveUnified(uint32_t, bool refocus = false);
@@ -96,6 +142,11 @@ 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;
}; };
inline std::unique_ptr<CInputManager> g_pInputManager; inline std::unique_ptr<CInputManager> g_pInputManager;

View File

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

View File

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

View File

@@ -2,21 +2,21 @@
#include "../../Compositor.hpp" #include "../../Compositor.hpp"
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) { if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && w->m_iID != SPECIAL_WORKSPACE_ID) {
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
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
@@ -28,44 +28,66 @@ void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor; m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor;
m_sActiveSwipe.avgSpeed = 0; m_sActiveSwipe.avgSpeed = 0;
m_sActiveSwipe.speedPoints = 0; m_sActiveSwipe.speedPoints = 0;
if (PWORKSPACE->m_bHasFullscreenWindow) {
for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
ls->alpha = 255.f;
}
}
} }
void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) { void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
if (!m_sActiveSwipe.pWorkspaceBegin) if (!m_sActiveSwipe.pWorkspaceBegin)
return; // no valid swipe return; // no valid swipe
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) && *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();
CWorkspace* pSwitchedTo = nullptr;
if ((abs(m_sActiveSwipe.delta) < *PSWIPEDIST * *PSWIPEPERC && (*PSWIPEFORC == 0 || (*PSWIPEFORC != 0 && m_sActiveSwipe.avgSpeed < *PSWIPEFORC))) || abs(m_sActiveSwipe.delta) < 2) { if ((abs(m_sActiveSwipe.delta) < *PSWIPEDIST * *PSWIPEPERC && (*PSWIPEFORC == 0 || (*PSWIPEFORC != 0 && m_sActiveSwipe.avgSpeed < *PSWIPEFORC))) || abs(m_sActiveSwipe.delta) < 2) {
// 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();
} }
pSwitchedTo = m_sActiveSwipe.pWorkspaceBegin;
} else if (m_sActiveSwipe.delta < 0) { } else if (m_sActiveSwipe.delta < 0) {
// switch to left // switch to left
const auto RENDEROFFSET = PWORKSPACEL->m_vRenderOffset.vec(); const auto RENDEROFFSET = PWORKSPACEL->m_vRenderOffset.vec();
@@ -76,37 +98,61 @@ 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_pCompositor->m_sSeat.mouse->currentConstraint = nullptr; g_pInputManager->unconstrainMouse();
Debug::log(LOG, "Ended swipe to the left"); Debug::log(LOG, "Ended swipe to the left");
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_pCompositor->m_sSeat.mouse->currentConstraint = nullptr; g_pInputManager->unconstrainMouse();
Debug::log(LOG, "Ended swipe to the right"); Debug::log(LOG, "Ended swipe to the right");
pSwitchedTo = PWORKSPACER;
} }
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;
g_pInputManager->refocus(); g_pInputManager->refocus();
// apply alpha
for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 255.f;
}
} }
void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) { void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
@@ -115,8 +161,11 @@ 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;
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++;
@@ -125,15 +174,22 @@ 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
return; return;
}
m_sActiveSwipe.pWorkspaceBegin->m_bForceRendering = true; m_sActiveSwipe.pWorkspaceBegin->m_bForceRendering = true;
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 || m_sActiveSwipe.pWorkspaceBegin->m_iID == workspaceIDRight) && *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;
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;
} }
@@ -141,19 +197,37 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
PWORKSPACE->m_bForceRendering = true; PWORKSPACE->m_bForceRendering = true;
PWORKSPACE->m_fAlpha.setValueAndWarp(255.f);
if (workspaceIDLeft != workspaceIDRight) { if (workspaceIDLeft != workspaceIDRight) {
const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight);
PWORKSPACER->m_bForceRendering = false; PWORKSPACER->m_bForceRendering = false;
PWORKSPACER->m_fAlpha.setValueAndWarp(0.f);
} }
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x - m_sActiveSwipe.pMonitor->vecSize.x, 0)); 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;
} }
@@ -161,15 +235,22 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight);
PWORKSPACE->m_bForceRendering = true; PWORKSPACE->m_bForceRendering = true;
PWORKSPACE->m_fAlpha.setValueAndWarp(255.f);
if (workspaceIDLeft != workspaceIDRight) { if (workspaceIDLeft != workspaceIDRight) {
const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
PWORKSPACEL->m_bForceRendering = false; PWORKSPACEL->m_bForceRendering = false;
PWORKSPACEL->m_fAlpha.setValueAndWarp(0.f);
} }
PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((- m_sActiveSwipe.delta) / *PSWIPEDIST) * m_sActiveSwipe.pMonitor->vecSize.x + m_sActiveSwipe.pMonitor->vecSize.x, 0)); 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);
} }

View File

@@ -66,7 +66,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER) if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER)
wlr_tablet_v2_tablet_tool_notify_slider(PTOOL->wlrTabletToolV2, EVENT->slider); wlr_tablet_v2_tablet_tool_notify_slider(PTOOL->wlrTabletToolV2, EVENT->slider);
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL) if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL)
wlr_tablet_v2_tablet_tool_notify_wheel(PTOOL->wlrTabletToolV2, EVENT->wheel_delta, 0); wlr_tablet_v2_tablet_tool_notify_wheel(PTOOL->wlrTabletToolV2, EVENT->wheel_delta, 0);
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X) if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X)
@@ -95,7 +95,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
else { else {
wlr_send_tablet_v2_tablet_tool_up(PTOOL->wlrTabletToolV2); wlr_send_tablet_v2_tablet_tool_up(PTOOL->wlrTabletToolV2);
} }
}, PNEWTABLET, "Tablet"); }, PNEWTABLET, "Tablet");
PNEWTABLET->hyprListener_Button.initCallback(&wlr_tablet_from_input_device(pDevice)->events.button, [](void* owner, void* data) { PNEWTABLET->hyprListener_Button.initCallback(&wlr_tablet_from_input_device(pDevice)->events.button, [](void* owner, void* data) {
@@ -104,7 +104,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool); const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
wlr_tablet_v2_tablet_tool_notify_button(PTOOL->wlrTabletToolV2, (zwp_tablet_pad_v2_button_state)EVENT->button, (zwp_tablet_pad_v2_button_state)EVENT->state); wlr_tablet_v2_tablet_tool_notify_button(PTOOL->wlrTabletToolV2, (zwp_tablet_pad_v2_button_state)EVENT->button, (zwp_tablet_pad_v2_button_state)EVENT->state);
}, PNEWTABLET, "Tablet"); }, PNEWTABLET, "Tablet");
PNEWTABLET->hyprListener_Proximity.initCallback(&wlr_tablet_from_input_device(pDevice)->events.proximity, [](void* owner, void* data) { PNEWTABLET->hyprListener_Proximity.initCallback(&wlr_tablet_from_input_device(pDevice)->events.proximity, [](void* owner, void* data) {
@@ -120,13 +120,13 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2); wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);
PTOOL->pSurface = nullptr; PTOOL->pSurface = nullptr;
} }
} else { } else {
PTOOL->active = true; PTOOL->active = true;
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pInputManager->focusTablet(PTAB, EVENT->tool); g_pInputManager->focusTablet(PTAB, EVENT->tool);
} }
}, PNEWTABLET, "Tablet"); }, PNEWTABLET, "Tablet");
} }
@@ -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

@@ -0,0 +1,75 @@
#include "InputManager.hpp"
#include "../../Compositor.hpp"
void CInputManager::onTouchDown(wlr_touch_down_event* e) {
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();
m_sTouchData.touchFocusWindow = m_pFoundWindowToFocus;
m_sTouchData.touchFocusSurface = m_pFoundSurfaceToFocus;
m_sTouchData.touchFocusLS = m_pFoundLSToFocus;
Vector2D local;
if (m_sTouchData.touchFocusWindow) {
if (m_sTouchData.touchFocusWindow->m_bIsX11) {
local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition.goalv();
} else {
g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), m_sTouchData.touchFocusWindow, 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;
m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local;
} else {
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);
}
void CInputManager::onTouchUp(wlr_touch_up_event* e){
if (m_sTouchData.touchFocusSurface) {
wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id);
}
}
void CInputManager::onTouchMove(wlr_touch_motion_event* e){
if (m_sTouchData.touchFocusWindow && g_pCompositor->windowValidMapped(m_sTouchData.touchFocusWindow)) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
} 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);
}
}
void CInputManager::onPointerHoldBegin(wlr_pointer_hold_begin_event* e) {
wlr_pointer_gestures_v1_send_hold_begin(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, e->time_msec, e->fingers);
}
void CInputManager::onPointerHoldEnd(wlr_pointer_hold_end_event* e) {
wlr_pointer_gestures_v1_send_hold_end(g_pCompositor->m_sWLRPointerGestures, g_pCompositor->m_sSeat.seat, e->time_msec, e->cancelled);
}

View File

@@ -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

@@ -3,7 +3,8 @@
bool CFramebuffer::alloc(int w, int h) { bool CFramebuffer::alloc(int w, int h) {
bool firstAlloc = false; bool firstAlloc = false;
RASSERT((w > 1 && h > 1), "cannot alloc a FB with negative / zero size! (attempted %ix%i)", w, h);
if (m_iFb == (uint32_t)-1) { if (m_iFb == (uint32_t)-1) {
firstAlloc = true; firstAlloc = true;
glGenFramebuffers(1, &m_iFb); glGenFramebuffers(1, &m_iFb);
@@ -73,8 +74,9 @@ 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();
} }

File diff suppressed because it is too large Load Diff

View File

@@ -8,16 +8,10 @@
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include "Shaders.hpp"
#include "Shader.hpp" #include "Shader.hpp"
#include "Texture.hpp" #include "Texture.hpp"
#include "Framebuffer.hpp" #include "Framebuffer.hpp"
inline const float matrixFlip180[] = {
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
@@ -33,8 +27,10 @@ inline const float fanVertsFull[] = {
struct SMonitorRenderData { struct SMonitorRenderData {
CFramebuffer primaryFB; CFramebuffer primaryFB;
CFramebuffer mirrorFB; CFramebuffer mirrorFB; // these are used for some effects,
CFramebuffer mirrorSwapFB; CFramebuffer mirrorSwapFB; // etc
CFramebuffer monitorMirrorFB; // used for mirroring outputs
CTexture stencilTex; CTexture stencilTex;
@@ -42,6 +38,18 @@ struct SMonitorRenderData {
bool blurFBDirty = true; bool blurFBDirty = true;
wlr_box backgroundTexBox; wlr_box backgroundTexBox;
// Shaders
bool m_bShadersInitialized = false;
CShader m_shQUAD;
CShader m_shRGBA;
CShader m_shRGBX;
CShader m_shEXT;
CShader m_shBLUR1;
CShader m_shBLUR2;
CShader m_shSHADOW;
CShader m_shBORDER1;
//
}; };
struct SCurrentRenderData { struct SCurrentRenderData {
@@ -54,6 +62,8 @@ 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 CHyprOpenGLImpl { class CHyprOpenGLImpl {
@@ -79,9 +89,9 @@ public:
void clear(const CColor&); void clear(const CColor&);
void clearWithTex(); void clearWithTex();
void scissor(const wlr_box*); void scissor(const wlr_box*, bool transform = true);
void scissor(const pixman_box32*); void scissor(const pixman_box32*, bool transform = true);
void scissor(const int x, const int y, const int w, const int h); void scissor(const int x, const int y, const int w, const int h, bool transform = true);
void destroyMonitorResources(CMonitor*); void destroyMonitorResources(CMonitor*);
@@ -90,6 +100,9 @@ public:
void preWindowPass(); void preWindowPass();
void preRender(CMonitor*); void preRender(CMonitor*);
void saveBufferForMirror();
void renderMirrored();
SCurrentRenderData m_RenderData; SCurrentRenderData m_RenderData;
GLint m_iCurrentOutputFb = 0; GLint m_iCurrentOutputFb = 0;
@@ -114,29 +127,18 @@ private:
bool m_bFakeFrame = false; bool m_bFakeFrame = false;
bool m_bEndFrame = false; bool m_bEndFrame = false;
// Shaders
CShader m_shQUAD;
CShader m_shRGBA;
CShader m_shRGBX;
CShader m_shEXT;
CShader m_shBLUR1;
CShader m_shBLUR2;
CShader m_shSHADOW;
CShader m_shBORDER1;
//
GLuint createProgram(const std::string&, const std::string&); GLuint createProgram(const std::string&, const std::string&);
GLuint compileShader(const GLuint&, std::string); GLuint compileShader(const GLuint&, std::string);
void createBGTextureForMonitor(CMonitor*); void createBGTextureForMonitor(CMonitor*);
void initShaders();
// returns the out FB, can be either Mirror or MirrorSwap // returns the out FB, can be either Mirror or MirrorSwap
CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage); CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage);
void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowCustomUV = false); void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowCustomUV = false, bool allowDim = false);
void renderSplash(cairo_t *const, cairo_surface_t *const, double);
void renderSplash(cairo_t *const, cairo_surface_t *const);
void preBlurForCurrentMonitor(); void preBlurForCurrentMonitor();
}; };
inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL; inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL;

View File

@@ -15,27 +15,26 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
if (RDATA->surface && surface == RDATA->surface) if (RDATA->surface && surface == RDATA->surface)
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, RDATA->w, RDATA->h}; windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, RDATA->w, RDATA->h};
else // here we clamp to 2, these might be some tiny specks else // here we clamp to 2, these might be some tiny specks
windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::clamp(surface->current.width, 2, 1337420), std::clamp(surface->current.height, 2, 1337420)}; windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max(surface->current.width, 2), std::max(surface->current.height, 2)};
// squish all oversized but dont in some cases, jesus christ this is a mess
// TODO: this shouldn't be done this way. Custom UV here as well.
// this is fucking horrible
// Issue: will cause oversized apps with reserved area to overflow from the window box. (see chromium on ozone wayland)
const auto PRESQUISHSIZE = Vector2D(windowBox.width, windowBox.height);
if (RDATA->squishOversized) { if (RDATA->squishOversized) {
if (x + windowBox.width > RDATA->w) if (x + windowBox.width > RDATA->w)
windowBox.width = RDATA->w - x; windowBox.width = RDATA->w - x;
if (y + windowBox.height > RDATA->h) if (y + windowBox.height > RDATA->h)
windowBox.height = RDATA->h - y; windowBox.height = RDATA->h - y;
} }
if (RDATA->pWindow)
g_pHyprRenderer->calculateUVForWindowSurface(RDATA->pWindow, surface, RDATA->squishOversized);
scaleBox(&windowBox, RDATA->output->scale); scaleBox(&windowBox, RDATA->output->scale);
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
static auto *const PBORDERTHICK = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? *PROUNDING : RDATA->rounding; float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? *PROUNDING : RDATA->rounding;
rounding += *PBORDERTHICK; rounding *= RDATA->output->scale;
rounding -= 1; // to fix a border issue
if (RDATA->surface && surface == RDATA->surface) { if (RDATA->surface && surface == RDATA->surface) {
if (wlr_surface_is_xwayland_surface(surface) && !wlr_xwayland_surface_from_wlr_surface(surface)->has_alpha && RDATA->fadeAlpha * RDATA->alpha == 255.f) { if (wlr_surface_is_xwayland_surface(surface) && !wlr_xwayland_surface_from_wlr_surface(surface)->has_alpha && RDATA->fadeAlpha * RDATA->alpha == 255.f) {
@@ -48,26 +47,16 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
} }
} }
else { else {
if (RDATA->surface && wlr_surface_is_xdg_surface(RDATA->surface)) { g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, true);
wlr_box geo;
wlr_xdg_surface_get_geometry(wlr_xdg_surface_from_wlr_surface(RDATA->surface), &geo);
// TODO: continuation of the above madness.
if (geo.x != 0 || geo.y != 0) {
windowBox.width = PRESQUISHSIZE.x;
windowBox.height = PRESQUISHSIZE.y;
}
windowBox.x -= geo.x;
windowBox.y -= geo.y;
}
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false);
} }
wlr_surface_send_frame_done(surface, RDATA->when); wlr_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
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
} }
bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) { bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
@@ -76,20 +65,27 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, CMonitor* pMonitor) {
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry)) if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry))
return false; return false;
if (pWindow->m_bPinned)
return true;
// now check if it has the same workspace // now check if it has the same workspace
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID) { if (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID) {
if (!(!PWORKSPACE->m_bHasFullscreenWindow || pWindow->m_bIsFullscreen || (pWindow->m_bIsFloating && pWindow->m_bCreatedOverFullscreen))) if (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated() || PWORKSPACE->m_bForceRendering) {
return false; return true;
} else {
if (!(!PWORKSPACE->m_bHasFullscreenWindow || pWindow->m_bIsFullscreen || (pWindow->m_bIsFloating && pWindow->m_bCreatedOverFullscreen)))
return false;
}
} }
if (pWindow->m_iWorkspaceID == pMonitor->activeWorkspace) if (pWindow->m_iWorkspaceID == pMonitor->activeWorkspace)
return true; return true;
// if not, check if it maybe is active on a different monitor. vvv might be animation in progress // if not, check if it maybe is active on a different monitor.
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && PWORKSPACE->m_bForceRendering) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))) if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) && pWindow->m_bIsFloating /* tiled windows can't be multi-ws */)
return true; return !pWindow->m_bIsFullscreen; // Do not draw fullscreen windows on other monitors
if (pMonitor->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) if (pMonitor->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
return true; return true;
@@ -104,6 +100,9 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (pWindow->m_bPinned || PWORKSPACE->m_bForceRendering)
return true;
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID)) if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID))
return true; return true;
@@ -121,11 +120,42 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) {
void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) { void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) {
CWindow* pWorkspaceWindow = nullptr; CWindow* pWorkspaceWindow = nullptr;
// loop over the tiled windows that are fading out
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID != pMonitor->activeWorkspace)
continue;
if (w->m_fAlpha.fl() == 0.f)
continue;
if (w->m_bIsFullscreen || w->m_bIsFloating)
continue;
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
}
// and floating ones too
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID != pMonitor->activeWorkspace)
continue;
if (w->m_fAlpha.fl() == 0.f)
continue;
if (w->m_bIsFullscreen || !w->m_bIsFloating)
continue;
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
}
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID);
if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen){ if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen){
if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))) if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated() || PWORKSPACE->m_bForceRendering)))
continue;
if (w->m_iMonitorID != pMonitor->ID)
continue; continue;
} }
@@ -137,9 +167,15 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
pWorkspaceWindow = w.get(); pWorkspaceWindow = w.get();
} }
// then render windows over fullscreen if (!pWorkspaceWindow) {
// ?? happens sometimes...
pWorkspace->m_bHasFullscreenWindow = false;
return; // this will produce one blank frame. Oh well.
}
// 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_bIsMapped) if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || !w->m_bIsMapped)
continue; continue;
renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL); renderWindow(w.get(), pMonitor, time, true, RENDER_PASS_ALL);
@@ -161,13 +197,12 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
} }
// and the overlay layers // and the overlay layers
if (pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL) { for (auto& ls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
// on non-full we draw the bar and shit if (ls->alpha.fl() != 0.f)
for (auto& ls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
renderLayer(ls.get(), pMonitor, time); renderLayer(ls.get(), pMonitor, time);
}
} }
for (auto& ls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { for (auto& ls : pMonitor->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
renderLayer(ls.get(), pMonitor, time); renderLayer(ls.get(), pMonitor, time);
} }
@@ -180,7 +215,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(CMonitor* pMonitor, CWor
} }
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) {
if (pWindow->m_bHidden) if (pWindow->isHidden())
return; return;
if (pWindow->m_bFadingOut) { if (pWindow->m_bFadingOut) {
@@ -188,21 +223,22 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
g_pHyprOpenGL->renderSnapshot(&pWindow); g_pHyprOpenGL->renderSnapshot(&pWindow);
return; return;
} }
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() + 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 const auto 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};
renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow); renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow);
renderdata.w = std::clamp(pWindow->m_vRealSize.vec().x, (double)5, (double)1337420); // 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::clamp(pWindow->m_vRealSize.vec().y, (double)5, (double)1337420); // 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
renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding); renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding);
renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (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 = pWindow->m_sAdditionalConfigData.rounding;
renderdata.blur = true; // if it shouldn't, it will be ignored later renderdata.blur = true; // if it shouldn't, it will be ignored later
renderdata.pWindow = pWindow;
// apply window special data // apply window special data
if (pWindow->m_sSpecialRenderData.alphaInactive == -1) if (pWindow->m_sSpecialRenderData.alphaInactive == -1)
@@ -216,50 +252,46 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
g_pHyprOpenGL->m_pCurrentWindow = pWindow; g_pHyprOpenGL->m_pCurrentWindow = pWindow;
// clip box for animated offsets
Vector2D offset;
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 > PWSMON->vecPosition.x + PWSMON->vecSize.x) {
offset.x = (WINBB.x - 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 > PWSMON->vecPosition.y + PWSMON->vecSize.y) {
offset.y = (WINBB.y - PWSMON->vecPosition.y + PWSMON->vecSize.y) * PROGRESS;
}
}
renderdata.x += offset.x;
renderdata.y += offset.y;
// render window decorations first, if not fullscreen full // 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);
if (!pWindow->m_bIsX11) {
wlr_box geom;
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
// first, check for poorly sized windows.
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D((double)geom.x / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)geom.y / (double)pWindow->m_uSurface.xdg->surface->current.height);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D((double)(geom.width + geom.x) / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)(geom.y + geom.height) / (double)pWindow->m_uSurface.xdg->surface->current.height);
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
// No special UV mods needed
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
// then, if the surface is too big, modify the pos UV
if (geom.width > renderdata.w + 1 || geom.height > renderdata.h + 1) {
const auto OFF = Vector2D(renderdata.w / (double)geom.width, renderdata.h / (double)geom.height);
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D(-1, -1))
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(0, 0);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x * ((double)renderdata.w / ((double)geom.width / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x)),
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y * ((double)renderdata.h / ((double)geom.height / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y))
);
}
} else {
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata); wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
if (renderdata.decorate) { if (renderdata.decorate && pWindow->m_sSpecialRenderData.border) {
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding; float rounding = renderdata.dontRound ? 0 : renderdata.rounding == -1 ? *PROUNDING : renderdata.rounding;
rounding *= pMonitor->scale;
auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col(); auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col();
col.a *= renderdata.fadeAlpha * renderdata.alpha / 255.f; col.a *= renderdata.fadeAlpha * renderdata.alpha / 255.f;
@@ -270,14 +302,17 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
g_pHyprOpenGL->renderBorder(&windowBox, col, rounding); g_pHyprOpenGL->renderBorder(&windowBox, col, rounding);
} }
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
} }
if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) { if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) {
if (!pWindow->m_bIsX11) { if (!pWindow->m_bIsX11) {
renderdata.dontRound = false; // restore dontround wlr_box geom;
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
renderdata.x -= geom.x;
renderdata.y -= geom.y;
renderdata.dontRound = true; // don't round popups
renderdata.pMonitor = pMonitor; renderdata.pMonitor = pMonitor;
renderdata.squishOversized = false; // don't squish popups renderdata.squishOversized = false; // don't squish popups
wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata); wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata);
@@ -285,6 +320,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) {
@@ -303,9 +339,22 @@ void CHyprRenderer::renderLayer(SLayerSurface* pLayer, CMonitor* pMonitor, times
wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata); wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata);
renderdata.squishOversized = false; // don't squish popups renderdata.squishOversized = false; // don't squish popups
renderdata.dontRound = true;
wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata); wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata);
} }
void CHyprRenderer::renderIMEPopup(SIMEPopup* pPopup, CMonitor* pMonitor, timespec* time) {
SRenderData renderdata = {pMonitor->output, time, pPopup->realX, pPopup->realY};
renderdata.blur = false;
renderdata.surface = pPopup->pSurface->surface;
renderdata.decorate = false;
renderdata.w = pPopup->pSurface->surface->current.width;
renderdata.h = pPopup->pSurface->surface->current.height;
wlr_surface_for_each_surface(pPopup->pSurface->surface, renderSurface, &renderdata);
}
void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(ID); const auto PMONITOR = g_pCompositor->getMonitorFromID(ID);
@@ -334,7 +383,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
// 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)
@@ -352,7 +401,7 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
// 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)
@@ -370,7 +419,7 @@ 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)
@@ -388,9 +437,9 @@ 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 (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID)
continue; continue;
@@ -405,6 +454,12 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
renderLayer(ls.get(), PMONITOR, time); renderLayer(ls.get(), PMONITOR, time);
} }
// Render IME popups
for (auto& imep : g_pInputManager->m_sIMERelay.m_lIMEPopups) {
renderIMEPopup(&imep, PMONITOR, time);
}
for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { for (auto& ls : PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
renderLayer(ls.get(), PMONITOR, time); renderLayer(ls.get(), PMONITOR, time);
} }
@@ -412,6 +467,72 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
renderDragIcon(PMONITOR, time); renderDragIcon(PMONITOR, time);
} }
void CHyprRenderer::calculateUVForWindowSurface(CWindow* pWindow, wlr_surface* pSurface, bool main) {
if (!pWindow->m_bIsX11) {
Vector2D uvTL;
Vector2D uvBR = Vector2D(1, 1);
wlr_box geom;
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
const auto SUBSURFACE = g_pXWaylandManager->getWindowSurface(pWindow) != pSurface && main;
// wp_viewporter_v1 implementation
if (pSurface->current.viewport.has_src) {
wlr_fbox bufferSource;
wlr_surface_get_buffer_source_box(pSurface, &bufferSource);
Vector2D surfaceSize = Vector2D(pSurface->buffer->texture->width, pSurface->buffer->texture->height);
uvTL = Vector2D(bufferSource.x / surfaceSize.x, bufferSource.y / surfaceSize.y);
uvBR = Vector2D((bufferSource.x + bufferSource.width) / surfaceSize.x, (bufferSource.y + bufferSource.height) / surfaceSize.y);
if (uvBR.x < 0.01f || uvBR.y < 0.01f) {
uvTL = Vector2D();
uvBR = Vector2D(1,1);
}
// TODO: (example: chromium) this still has a tiny "bump" at the end.
if (main) {
uvTL = uvTL + (Vector2D((double)geom.x / ((double)pWindow->m_uSurface.xdg->surface->current.width), (double)geom.y / ((double)pWindow->m_uSurface.xdg->surface->current.height)) * (((uvBR.x - uvTL.x) * surfaceSize.x) / surfaceSize.x));
uvBR = uvBR * Vector2D((double)(geom.width + geom.x) / ((double)pWindow->m_uSurface.xdg->surface->current.width), (double)(geom.y + geom.height) / ((double)pWindow->m_uSurface.xdg->surface->current.height));
}
} else if (main) {
// oversized windows' UV adjusting
uvTL = Vector2D((double)geom.x / ((double)pWindow->m_uSurface.xdg->surface->current.width), (double)geom.y / ((double)pWindow->m_uSurface.xdg->surface->current.height));
uvBR = Vector2D((double)(geom.width + geom.x) / ((double)pWindow->m_uSurface.xdg->surface->current.width), (double)(geom.y + geom.height) / ((double)pWindow->m_uSurface.xdg->surface->current.height));
}
// set UV
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL;
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR;
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
// No special UV mods needed
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
if (!main)
return; // ignore the rest
// then, if the surface is too big, modify the pos UV
if ((geom.width > pWindow->m_vRealSize.vec().x + 1 || geom.height > pWindow->m_vRealSize.vec().y + 1) && !SUBSURFACE) {
const auto OFF = Vector2D(pWindow->m_vRealSize.vec().x / (double)geom.width, pWindow->m_vRealSize.vec().y / (double)geom.height);
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D(-1, -1))
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(0, 0);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x * (pWindow->m_vRealSize.vec().x / ((double)geom.width / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.x)),
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y * (pWindow->m_vRealSize.vec().y / ((double)geom.height / g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight.y)));
}
} else {
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
}
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;
@@ -639,14 +760,22 @@ 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)
damageMonitor(PMONITOR); damageMonitor(PMONITOR);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitor);
Debug::log(LOG, "Monitor %s layers arranged: reserved: %f %f %f %f", PMONITOR->szName.c_str(), PMONITOR->vecReservedTopLeft.x, PMONITOR->vecReservedTopLeft.y, PMONITOR->vecReservedBottomRight.x, PMONITOR->vecReservedBottomRight.y); Debug::log(LOG, "Monitor %s layers arranged: reserved: %f %f %f %f", PMONITOR->szName.c_str(), PMONITOR->vecReservedTopLeft.x, PMONITOR->vecReservedTopLeft.y, PMONITOR->vecReservedBottomRight.x, PMONITOR->vecReservedBottomRight.y);
} }
@@ -654,6 +783,9 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
if (!pSurface) if (!pSurface)
return; // wut? return; // wut?
if (g_pCompositor->m_bUnsafeState)
return;
pixman_region32_t damageBox; pixman_region32_t damageBox;
pixman_region32_init(&damageBox); pixman_region32_init(&damageBox);
wlr_surface_get_effective_damage(pSurface, &damageBox); wlr_surface_get_effective_damage(pSurface, &damageBox);
@@ -680,7 +812,7 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
wlr_region_scale(&damageBoxForEach, &damageBoxForEach, m->scale); wlr_region_scale(&damageBoxForEach, &damageBoxForEach, m->scale);
pixman_region32_translate(&damageBoxForEach, lx + m->vecPosition.x, ly + m->vecPosition.y); pixman_region32_translate(&damageBoxForEach, lx + m->vecPosition.x, ly + m->vecPosition.y);
wlr_output_damage_add(m->damage, &damageBoxForEach); m->addDamage(&damageBoxForEach);
} }
pixman_region32_fini(&damageBoxForEach); pixman_region32_fini(&damageBoxForEach);
@@ -694,22 +826,28 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
} }
void CHyprRenderer::damageWindow(CWindow* pWindow) { void CHyprRenderer::damageWindow(CWindow* pWindow) {
if (g_pCompositor->m_bUnsafeState)
return;
wlr_box damageBox = pWindow->getFullWindowBoundingBox(); wlr_box damageBox = pWindow->getFullWindowBoundingBox();
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
wlr_box fixedDamageBox = {damageBox.x - m->vecPosition.x, damageBox.y - m->vecPosition.y, damageBox.width, damageBox.height}; wlr_box fixedDamageBox = {damageBox.x - m->vecPosition.x, damageBox.y - m->vecPosition.y, damageBox.width, damageBox.height};
scaleBox(&fixedDamageBox, m->scale); scaleBox(&fixedDamageBox, m->scale);
wlr_output_damage_add_box(m->damage, &fixedDamageBox); m->addDamage(&fixedDamageBox);
} }
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE) if (*PLOGDAMAGE)
Debug::log(LOG, "Damage: Window (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); Debug::log(LOG, "Damage: Window (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height);
} }
void CHyprRenderer::damageMonitor(CMonitor* pMonitor) { void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
if (g_pCompositor->m_bUnsafeState || pMonitor->isMirror())
return;
wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y}; wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
wlr_output_damage_add_box(pMonitor->damage, &damageBox); pMonitor->addDamage(&damageBox);
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
@@ -718,10 +856,16 @@ void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
} }
void CHyprRenderer::damageBox(wlr_box* pBox) { void CHyprRenderer::damageBox(wlr_box* pBox) {
if (g_pCompositor->m_bUnsafeState)
return;
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (m->isMirror())
continue; // don't damage mirrors traditionally
wlr_box damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height}; wlr_box damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height};
scaleBox(&damageBox, m->scale); scaleBox(&damageBox, m->scale);
wlr_output_damage_add_box(m->damage, &damageBox); m->addDamage(&damageBox);
} }
static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
@@ -742,6 +886,19 @@ void CHyprRenderer::damageRegion(pixman_region32_t* rg) {
} }
} }
void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, pixman_region32_t* pRegion) {
for (auto& mirror : pMonitor->mirrors) {
Vector2D scale = {mirror->vecSize.x / pMonitor->vecSize.x, mirror->vecSize.y / pMonitor->vecSize.y};
pixman_region32_t rg;
pixman_region32_init(&rg);
pixman_region32_copy(&rg, pRegion);
wlr_region_scale_xy(&rg, &rg, scale.x, scale.y);
pMonitor->addDamage(&rg);
pixman_region32_fini(&rg);
}
}
void CHyprRenderer::renderDragIcon(CMonitor* pMonitor, timespec* time) { void CHyprRenderer::renderDragIcon(CMonitor* pMonitor, timespec* time) {
if (!(g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.iconMapped && g_pInputManager->m_sDrag.dragIcon->surface)) if (!(g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.iconMapped && g_pInputManager->m_sDrag.dragIcon->surface))
return; return;
@@ -778,7 +935,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
if (pMonitor->m_bEnabled) if (pMonitor->m_bEnabled)
pMonitor->onDisconnect(); pMonitor->onDisconnect();
return false; return true;
} }
if (!pMonitor->m_bEnabled) { if (!pMonitor->m_bEnabled) {
@@ -787,7 +944,15 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} }
// Check if the rule isn't already applied // Check if the rule isn't already applied
if (!force && DELTALESSTHAN(pMonitor->vecPixelSize.x, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(pMonitor->vecPixelSize.y, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1) && pMonitor->scale == pMonitorRule->scale && DELTALESSTHAN(pMonitor->vecPosition.x, pMonitorRule->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, pMonitorRule->offset.y, 1) && pMonitor->transform == pMonitorRule->transform) { if (!force
&& DELTALESSTHAN(pMonitor->vecPixelSize.x, pMonitorRule->resolution.x, 1)
&& DELTALESSTHAN(pMonitor->vecPixelSize.y, pMonitorRule->resolution.y, 1)
&& DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1)
&& pMonitor->scale == pMonitorRule->scale
&& ((DELTALESSTHAN(pMonitor->vecPosition.x, pMonitorRule->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, pMonitorRule->offset.y, 1)) || pMonitorRule->offset == Vector2D(-1, -1))
&& pMonitor->transform == pMonitorRule->transform
&& 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;
} }
@@ -795,10 +960,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;
// loop over modes and choose an appropriate one. // loop over modes and choose an appropriate one.
if (pMonitorRule->resolution != Vector2D()) { if (pMonitorRule->resolution != Vector2D() && pMonitorRule->resolution != Vector2D(-1,-1) && pMonitorRule->resolution != Vector2D(-1,-2)) {
if (!wl_list_empty(&pMonitor->output->modes)) { if (!wl_list_empty(&pMonitor->output->modes)) {
wlr_output_mode* mode; wlr_output_mode* mode;
bool found = false; bool found = false;
@@ -831,6 +994,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
if (!found) { if (!found) {
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000); wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
pMonitor->vecSize = pMonitorRule->resolution; pMonitor->vecSize = pMonitorRule->resolution;
pMonitor->refreshRate = pMonitorRule->refreshRate;
if (!wlr_output_test(pMonitor->output)) { if (!wlr_output_test(pMonitor->output)) {
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
@@ -859,6 +1023,95 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} else { } else {
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000); wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000);
pMonitor->vecSize = pMonitorRule->resolution; pMonitor->vecSize = pMonitorRule->resolution;
pMonitor->refreshRate = pMonitorRule->refreshRate;
if (!wlr_output_test(pMonitor->output)) {
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f", (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
return true;
}
// Preferred is valid
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f", pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
} else {
Debug::log(LOG, "Set a custom mode %ix%i@%2f (mode not found in monitor modes)", (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
}
}
} else if (pMonitorRule->resolution != Vector2D()) {
if (!wl_list_empty(&pMonitor->output->modes)) {
wlr_output_mode* mode;
float currentWidth = 0;
float currentHeight = 0;
float currentRefresh = 0;
bool success = false;
//(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution
if(pMonitorRule->resolution == Vector2D(-1,-1)) {
wl_list_for_each(mode, &pMonitor->output->modes, link) {
if( ( mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= ( currentRefresh - 1000.f ) ) || mode->refresh > ( currentRefresh + 3000.f ) ) {
wlr_output_set_mode(pMonitor->output, mode);
if (wlr_output_test(pMonitor->output)) {
currentWidth = mode->width;
currentHeight = mode->height;
currentRefresh = mode->refresh;
success = true;
}
}
}
} else {
wl_list_for_each(mode, &pMonitor->output->modes, link) {
if( ( mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= ( currentRefresh - 1000.f ) ) || ( mode->width > currentWidth && mode->height > currentHeight ) ) {
wlr_output_set_mode(pMonitor->output, mode);
if (wlr_output_test(pMonitor->output)) {
currentWidth = mode->width;
currentHeight = mode->height;
currentRefresh = mode->refresh;
success = true;
}
}
}
}
if (!success) {
Debug::log(LOG, "Monitor %s: REJECTED mode: %ix%i@%2f! Falling back to preferred.",
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
mode->width, mode->height, mode->refresh / 1000.f);
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f",
(int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate);
return true;
}
// Preferred is valid
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f",
pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate,
PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
} else {
Debug::log(LOG, "Monitor %s: Applying highest mode %ix%i@%2f.",
pMonitor->output->name, (int)currentWidth, (int)currentHeight, (int)currentRefresh / 1000.f,
mode->width, mode->height, mode->refresh / 1000.f);
pMonitor->refreshRate = currentRefresh / 1000.f;
pMonitor->vecSize = Vector2D(currentWidth, currentHeight);
}
} }
} else { } else {
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
@@ -896,17 +1149,42 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
Debug::log(LOG, "Setting preferred mode for %s", pMonitor->output->name);
} }
} }
pMonitor->vrrActive = pMonitor->output->pending.adaptive_sync_enabled; // disabled here, will be tested in CConfigManager::ensureVRR()
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform); wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
pMonitor->transform = pMonitorRule->transform; pMonitor->transform = pMonitorRule->transform;
pMonitor->vecPixelSize = pMonitor->vecSize; pMonitor->vecPixelSize = pMonitor->vecSize;
// update renderer if (pMonitorRule->enable10bit) {
g_pHyprOpenGL->destroyMonitorResources(pMonitor); // try 10b RGB
wlr_output_set_render_format(pMonitor->output, DRM_FORMAT_XRGB2101010);
pMonitor->enabled10bit = true;
if (!wlr_output_test(pMonitor->output)) {
Debug::log(ERR, "Output %s -> 10 bit enabled, but failed format DRM_FORMAT_XRGB2101010. Trying BGR.", pMonitor->output->name);
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;
}
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);
@@ -918,13 +1196,31 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor(); pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).floor();
pMonitor->vecTransformedSize = Vector2D(x,y); pMonitor->vecTransformedSize = Vector2D(x,y);
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitorRule->offset.x, (int)pMonitorRule->offset.y); if (pMonitorRule->offset == Vector2D(-1, -1) && pMonitor->vecPosition == Vector2D(-1, -1)) {
// let's find manually a sensible position for it, to the right.
Vector2D finalPos;
//wlr_output_damage_add_whole(pMonitor->damage); for (auto& m : g_pCompositor->m_vMonitors) {
if (m->ID == pMonitor->ID)
continue;
if (m->vecPosition.x + std::ceil(m->vecSize.x) > finalPos.x) {
finalPos.x = m->vecPosition.x + std::ceil(m->vecSize.x);
}
}
pMonitor->vecPosition = finalPos;
} else if (pMonitorRule->offset != Vector2D(-1, -1)) {
pMonitor->vecPosition = pMonitorRule->offset;
}
wlr_output_enable(pMonitor->output, true); wlr_output_enable(pMonitor->output, true);
// update renderer (here because it will call rollback, so we cannot do this before committing)
g_pHyprOpenGL->destroyMonitorResources(pMonitor);
// updato wlroots // updato wlroots
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y);
Events::listener_change(nullptr, nullptr); Events::listener_change(nullptr, nullptr);
// updato us // updato us
@@ -933,6 +1229,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
// frame skip // frame skip
pMonitor->framesToSkip = 1; pMonitor->framesToSkip = 1;
// reload to fix mirrors
g_pConfigManager->m_bWantsMonitorReload = true;
return true; return true;
} }

View File

@@ -35,11 +35,13 @@ public:
void damageBox(const int& x, const int& y, const int& w, const int& h); void damageBox(const int& x, const int& y, const int& w, const int& h);
void damageRegion(pixman_region32_t*); void damageRegion(pixman_region32_t*);
void damageMonitor(CMonitor*); void damageMonitor(CMonitor*);
void damageMirrorsWith(CMonitor*, pixman_region32_t*);
bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false); bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
bool shouldRenderWindow(CWindow*, CMonitor*); bool shouldRenderWindow(CWindow*, CMonitor*);
bool shouldRenderWindow(CWindow*); bool shouldRenderWindow(CWindow*);
void ensureCursorRenderingMode(); void ensureCursorRenderingMode();
bool shouldRenderCursor(); bool shouldRenderCursor();
void calculateUVForWindowSurface(CWindow*, wlr_surface*, bool main = false);
bool m_bWindowRequestedCursorHide = false; bool m_bWindowRequestedCursorHide = false;
@@ -51,6 +53,7 @@ private:
void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode); void renderWindow(CWindow*, CMonitor*, timespec*, bool, eRenderPassMode);
void renderLayer(SLayerSurface*, CMonitor*, timespec*); void renderLayer(SLayerSurface*, CMonitor*, timespec*);
void renderDragIcon(CMonitor*, timespec*); void renderDragIcon(CMonitor*, timespec*);
void renderIMEPopup(SIMEPopup*, CMonitor*, timespec*);
bool m_bHasARenderedCursor = true; bool m_bHasARenderedCursor = true;

View File

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

View File

@@ -5,7 +5,9 @@
class CShader { class CShader {
public: public:
GLuint program; ~CShader();
GLuint program = 0;
GLint proj; GLint proj;
GLint color; GLint color;
GLint tex; GLint tex;
@@ -27,6 +29,9 @@ public:
GLint range; GLint range;
GLint shadowPower; GLint shadowPower;
GLint applyTint;
GLint tint;
GLint getUniformLocation(const std::string&); GLint getUniformLocation(const std::string&);
private: private:

View File

@@ -38,7 +38,7 @@ void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
const auto WORKSPACEOFFSET = PWORKSPACE ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D(); const auto WORKSPACEOFFSET = PWORKSPACE && !pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) {
m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET; m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET;
@@ -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;
@@ -56,68 +56,68 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) {
if (m_pWindow->m_cRealShadowColor.col() == CColor(0, 0, 0, 0)) if (m_pWindow->m_cRealShadowColor.col() == CColor(0, 0, 0, 0))
return; // don't draw invisible shadows return; // don't draw invisible shadows
if (!m_pWindow->m_sSpecialRenderData.decorate)
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 PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->strValue; static auto *const PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->vecValue;
if (*PSHADOWS != 1) if (*PSHADOWS != 1)
return; // disabled return; // disabled
// get the real offset const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ? 0 : (m_pWindow->m_sAdditionalConfigData.rounding == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding);
Vector2D offset;
try {
if (const auto SPACEPOS = PSHADOWOFFSET->find(' '); SPACEPOS != std::string::npos) {
const auto X = PSHADOWOFFSET->substr(0, SPACEPOS);
const auto Y = PSHADOWOFFSET->substr(SPACEPOS + 1);
if (isNumber(X, true) && isNumber(Y, true)) {
offset = Vector2D(std::stof(X), std::stof(Y));
}
}
} catch (std::exception& e) {
return; // cannot parse
}
// update the extents // update the extents
m_seExtents = {{*PSHADOWSIZE + 2 - offset.x, *PSHADOWSIZE + 2 - offset.y}, {*PSHADOWSIZE + 2 + offset.x, *PSHADOWSIZE + 2 + offset.y}}; m_seExtents = {{*PSHADOWSIZE + 2 - 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 - 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};
fullBox.x -= pMonitor->vecPosition.x; fullBox.x -= pMonitor->vecPosition.x;
fullBox.y -= pMonitor->vecPosition.y; fullBox.y -= pMonitor->vecPosition.y;
fullBox.x += offset.x;
fullBox.y += offset.y;
if (fullBox.width < 1 || fullBox.height < 1) if (fullBox.width < 1 || fullBox.height < 1)
return; // don't draw invisible shadows return; // don't draw invisible shadows
g_pHyprOpenGL->scissor((wlr_box *)nullptr);
if (*PSHADOWIGNOREWINDOW) { if (*PSHADOWIGNOREWINDOW) {
glEnable(GL_STENCIL_TEST);
glClearStencil(0); glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT); glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, -1); glStencilFunc(GL_ALWAYS, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
wlr_box windowBox = {m_vLastWindowPos.x - pMonitor->vecPosition.x, m_vLastWindowPos.y - pMonitor->vecPosition.y, m_vLastWindowSize.x, m_vLastWindowSize.y}; wlr_box windowBox = {m_vLastWindowPos.x - pMonitor->vecPosition.x, m_vLastWindowPos.y - pMonitor->vecPosition.y, m_vLastWindowSize.x, m_vLastWindowSize.y};
scaleBox(&windowBox, pMonitor->scale); scaleBox(&windowBox, pMonitor->scale);
if (windowBox.width < 1 || windowBox.height < 1) { if (windowBox.width < 1 || windowBox.height < 1) {
glDisable(GL_STENCIL_TEST); glClearStencil(0);
return; // prevent assert failed glClear(GL_STENCIL_BUFFER_BIT);
glDisable(GL_STENCIL_TEST);
return; // prevent assert failed
} }
g_pHyprOpenGL->renderRect(&windowBox, CColor(0,0,0,0), *PROUNDING); g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 0), ROUNDING * pMonitor->scale);
glStencilFunc(GL_NOTEQUAL, 1, -1); glStencilFunc(GL_NOTEQUAL, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
} }
scaleBox(&fullBox, pMonitor->scale); scaleBox(&fullBox, pMonitor->scale);
g_pHyprOpenGL->renderRoundedShadow(&fullBox, *PROUNDING, *PSHADOWSIZE, a); g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, a);
if (*PSHADOWIGNOREWINDOW) { if (*PSHADOWIGNOREWINDOW) {
// cleanup // cleanup

View File

@@ -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

@@ -3,7 +3,6 @@
CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) { CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) {
m_pWindow = pWindow; m_pWindow = pWindow;
updateWindow(pWindow);
} }
CHyprGroupBarDecoration::~CHyprGroupBarDecoration() { CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {
@@ -23,13 +22,13 @@ void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
const auto WORKSPACEOFFSET = PWORKSPACE ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D(); const auto WORKSPACEOFFSET = PWORKSPACE && !pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D();
if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) {
// we draw 3px above the window's border with 3px // we draw 3px above the window's border with 3px
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); const auto PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
m_seExtents.topLeft = Vector2D(0, BORDERSIZE + 3 + 3); m_seExtents.topLeft = Vector2D(0, *PBORDERSIZE + 3 + 3);
m_seExtents.bottomRight = Vector2D(); m_seExtents.bottomRight = Vector2D();
m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET; m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET;
@@ -46,7 +45,7 @@ void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) {
// get the group info // get the group info
SLayoutMessageHeader header; SLayoutMessageHeader header;
header.pWindow = g_pCompositor->m_pLastWindow; header.pWindow = m_pWindow;
m_dwGroupMembers = std::any_cast<std::deque<CWindow*>>(g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "groupinfo")); m_dwGroupMembers = std::any_cast<std::deque<CWindow*>>(g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "groupinfo"));
@@ -64,11 +63,14 @@ 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;
if (!m_pWindow->m_sSpecialRenderData.decorate)
return; return;
const int PAD = 2; //2px const int PAD = 2; //2px
@@ -78,12 +80,17 @@ 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;
CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? CColor(g_pConfigManager->getInt("dwindle:col.group_border_active")) : CColor(g_pConfigManager->getInt("dwindle:col.group_border")); scaleBox(&rect, pMonitor->scale);
static auto *const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border_active")->intValue;
static auto *const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:col.group_border")->intValue;
CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? CColor(*PGROUPCOLACTIVE) : CColor(*PGROUPCOLINACTIVE);
color.a *= a; color.a *= a;
g_pHyprOpenGL->renderRect(&rect, color); g_pHyprOpenGL->renderRect(&rect, color);

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

@@ -3,5 +3,5 @@
#include "../../Window.hpp" #include "../../Window.hpp"
IHyprWindowDecoration::~IHyprWindowDecoration() { IHyprWindowDecoration::~IHyprWindowDecoration() {
} }

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

@@ -42,7 +42,7 @@ void main() {
vec4 pixColor = v_color; vec4 pixColor = v_color;
bool done = false; bool done = false;
// check for edges // check for edges
if (pixCoord[0] < topLeft[0]) { if (pixCoord[0] < topLeft[0]) {
if (pixCoord[1] < topLeft[1]) { if (pixCoord[1] < topLeft[1]) {
@@ -88,4 +88,4 @@ void main() {
gl_FragColor = pixColor; gl_FragColor = pixColor;
} }
)#"; )#";

View File

@@ -59,7 +59,7 @@ void main() {
} }
} }
if (!done) { if (!done) {
// distance to all straight bb borders // distance to all straight bb borders
float distanceT = pixCoord[1]; float distanceT = pixCoord[1];
float distanceB = fullSize[1] - pixCoord[1]; float distanceB = fullSize[1] - pixCoord[1];
@@ -79,4 +79,4 @@ void main() {
} }
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,30 +90,33 @@ 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;
uniform int discardOpaque; uniform int discardOpaque;
uniform int applyTint;
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;
}
vec2 pixCoord = fullSize * v_texcoord;
)#" + ROUNDED_SHADER_FUNC("pixColor") + if (applyTint == 1) {
R"#( pixColor[0] = pixColor[0] * tint[0];
pixColor[1] = pixColor[1] * tint[1];
pixColor[2] = pixColor[2] * tint[2];
}
gl_FragColor = pixColor * alpha; )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
gl_FragColor = pixColor * alpha;
})#"; })#";
inline const std::string TEXFRAGSRCRGBX = R"#( inline const std::string TEXFRAGSRCRGBX = R"#(
@@ -232,29 +126,32 @@ 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;
uniform int discardOpaque; uniform int discardOpaque;
uniform int applyTint;
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);
vec2 pixCoord = fullSize * v_texcoord;
)#" + ROUNDED_SHADER_FUNC("pixColor") + R"#( if (applyTint == 1) {
pixColor[0] = pixColor[0] * tint[0];
pixColor[1] = pixColor[1] * tint[1];
pixColor[2] = pixColor[2] * tint[2];
}
gl_FragColor = pixColor * alpha; )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
gl_FragColor = pixColor * alpha;
})#"; })#";
inline const std::string FRAGBLUR1 = R"#( inline const std::string FRAGBLUR1 = R"#(
@@ -267,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;
} }
)#"; )#";
@@ -288,10 +186,10 @@ 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);
sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0; sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius); sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0; sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0;
@@ -313,27 +211,31 @@ 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;
uniform int discardOpaque; uniform int discardOpaque;
uniform int applyTint;
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;
}
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") + R"#( )#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
gl_FragColor = pixColor * alpha; gl_FragColor = pixColor * alpha;
})#"; }
)#";

View File

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