Compare commits

...

486 Commits

Author SHA1 Message Date
Vaxry
3bb9c7c5cf props: bump ver to 0.33.0 2023-12-05 00:52:16 +00:00
Vaxry
2d04cb1cc6 input: make fallback layout us 2023-12-05 00:48:39 +00:00
Vaxry
c6804ccaab opengl: fixup blur dirty repaint conditions with solitary
fixes #4025
2023-12-05 00:43:09 +00:00
Glizda
aa46aaed04 config: Add variables to default config (#4032)
* update default config

* Fix inconsistency in variable naming

* continuation of last commit

* edited example/hyprland.conf for parity

* fix  issue

* deleted unwanted newline
2023-12-04 18:47:58 +00:00
Vaxry
68783d904d screencopy: use buffer format for glReadPixels
fixes #4029
2023-12-04 03:52:54 +00:00
Vaxry
5d100bdcbb opengl: clear layer fade fbs in ~dtor 2023-12-04 02:08:34 +00:00
Vaxry
45d3fbb8d8 opengl: free window framebuffers in ~dtor
ref #4036
2023-12-04 01:44:16 +00:00
dranull
9a9528d093 config: Minor --config improvements, fixes (#4034)
* Follow symlink, only file, absolute path for -c

* Create config file only for default paths

* Skip non-file source= glob results

* Check for absolute path on XDG_CONFIG_HOME

As per spec, all non-absolute paths should be ignored.
https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
2023-12-04 01:35:24 +00:00
Vaxry
e496b0f250 screencopy: fix detecting gl shm formats
ref #4029
2023-12-03 22:04:07 +00:00
Vaxry
dc2082b00a screencopy: fix transformed on shm 2023-12-03 19:06:51 +00:00
dranull
59cb0e20de input: Handle fullscreen windows in vectorToWindowIdeal (#4021) 2023-12-03 12:53:12 +00:00
Vaxry
80b9b21f9f opengl: fix nvidia read formats
fixes #4023
2023-12-02 14:51:45 +00:00
thejch
758cf90ea1 workspacerules: Add workspace rule for master layout orientation (#3964)
* add workspace rule for master layout orientation

* change rule format

* edit rule name

* use map for layoutopts

* use std::any instead of string
2023-12-02 14:42:49 +00:00
Vaxry
6e8b9ef7d8 opengl: fix swapped rgb drm formats 2023-12-01 17:23:50 +00:00
Vaxry
9c09f2a847 screencopy: fix shm exports with 10-bit
fixes #4019
2023-12-01 17:20:56 +00:00
Wren Baxter
8440a30231 input: fix overzealous mouse capture on resize_on_border (#4010)
fixes #2456
2023-12-01 01:12:08 +00:00
Vaxry
ab40f240c3 screencopy: use drmFormat instead of wlr funcs
ref #4014
2023-12-01 00:23:48 +00:00
vaxerski
b394c1695c [gha] Nix: update wlroots 2023-11-30 18:53:34 +00:00
Vaxry
0a4c4da5f0 deps: update wlroots 2023-11-30 18:52:49 +00:00
Vaxry
b2f3623131 events: add keyPress and mouseAxis
fixes #4011 fixes #4008
2023-11-30 18:45:12 +00:00
François Conzelmann
5513eed64d managers: fix debug log using printf format (#4007)
Some debug messages where using printf format style to print variable
content instead of std::format format.
2023-11-30 15:20:08 +00:00
André Silva
29970228c5 nix: override libdrm to use newer version (#4003) 2023-11-30 11:40:14 +00:00
vaxerski
12ec549a18 screencopy: fix shm sharing if introspection required 2023-11-30 11:07:17 +00:00
Vaxry
9f2027be4b opengl: don't make a mirror buffer on fakeFrame 2023-11-30 10:15:02 +00:00
Vaxry
b9937484f4 screencopy: fix broken shm copying
fixes #4001
2023-11-30 10:14:35 +00:00
Vaxry
776f944619 opengl: fix missed makeEGLCurrent
fixes #3998
2023-11-30 02:19:27 +00:00
François Conzelmann
1fc1e4e9cb monitor: remove comma from monitor description (#3996)
this allows for monitor specific rules to work on monitor with comma on
their description

fixes #2457
2023-11-30 01:48:10 +00:00
vaxerski
e1258707ad [gha] Nix: update wlroots 2023-11-30 01:19:51 +00:00
Vaxry
d2c3b23ace deps: update wlroots 2023-11-30 01:18:55 +00:00
Vaxry
b80c72c7dd groupbar: fix crash in renderGradientTo
fixes #3985
2023-11-29 13:36:37 +00:00
Vaxry
3caaa483d4 configmgr: fix parsing of touchdevice groups
fixes #3992
2023-11-29 03:39:45 +00:00
Vaxry
e2f18f8c7f groupbar: more safety around gradient textures 2023-11-28 19:03:02 +00:00
Vaxry
99ca26d4eb hooksystem: fix missed log include 2023-11-26 18:33:53 +00:00
Vaxry
e416ab740d config: log info about logs before loading vars 2023-11-26 18:02:33 +00:00
MightyPlaza
7a0a5666d5 groupbar: allow reload and fix locked groupbar gradient (#3546)
modified:   src/config/ConfigManager.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.hpp
2023-11-26 17:59:49 +00:00
Vaxry
1778fb77e2 functionhooks: throw an exception on unsupported %rip usage
ref #2479, now will actually tell you what's wrong instead of crashing
2023-11-26 17:53:51 +00:00
Vaxry
adeb20ea11 opengl: tiled special require introspection 2023-11-26 16:42:04 +00:00
Vaxry
68e57b7ee3 renderer: proper full occlusion checks for back layer 2023-11-26 15:24:24 +00:00
Vaxry
408d96668d renderer: use occlusion checks for buffer clear 2023-11-26 15:06:42 +00:00
Vaxry
75e5799310 layer-shell: simulate mouse movement on unmap 2023-11-26 14:54:34 +00:00
Vaxry
9e2b939024 surface: avoid infinite pointer image resets
fixes #3729, should also #3968
2023-11-26 14:53:22 +00:00
Vaxry
cd96ceecc5 build: remove nv patches (#3957) 2023-11-26 02:58:57 +00:00
Vaxry
ad3f688648 opengl: check for introspection on special_blur 2023-11-25 19:44:34 +00:00
vaxerski
98c7ba4782 [gha] Nix: update wlroots 2023-11-25 19:25:44 +00:00
Vaxry
a5f64b48ca deps: downgrade wlroots to fix crashes 2023-11-25 19:24:59 +00:00
Vaxry
b281d8647a screencopy: use new isNvidia() for format 2023-11-25 17:56:38 +00:00
Vaxry
15b282ee0c opengl: fix window introspection check 2023-11-25 17:46:50 +00:00
Vaxry
6f733292bf renderer: nvidia checks and use glFinish on nvidia
fixes #3952 #3946
2023-11-25 17:45:08 +00:00
Vaxry
3fe6162af1 opengl: fix xray modes in introspection checks for ls
fixes #3953
2023-11-25 14:52:52 +00:00
Jibin George
2ce4b94a22 input: Fix custom acceleration profile config (#3948) 2023-11-25 14:39:21 +00:00
coldified
de95e956a0 meson: Update wlroots-meson-build.patch (#3950) 2023-11-25 14:32:01 +00:00
Junxuan Liao
929c44e361 input: pass mouse input to IME popups (#3922) 2023-11-25 14:27:57 +00:00
Vaxry
512a59731b config: default special_scale_factor to 1 2023-11-25 01:45:04 +00:00
Vaxry
a6eba91935 opengl: require introspection on mirroring
fixes #3939
2023-11-25 00:48:02 +00:00
Xavier
745b998587 renderer: Adding an option to disable first launch animation (#3933) 2023-11-24 21:45:59 +00:00
Vaxry
1a2a2da6aa renderer: fixup cursor scaling
fixes #3935
2023-11-24 21:30:28 +00:00
Vaxry
822775aa8c renderer: Fixup double rendering cases with special (#3928)
* fixup

* better fullscreen
2023-11-24 21:18:50 +00:00
Vaxry
d79cf0afe2 renderer: fix software cursors on nvidia
fixes #3926
2023-11-24 13:47:36 +00:00
Vaxry
334d0ae31b monitor: fix transform matrix calculations for transformed
fixes #3929
2023-11-24 13:45:10 +00:00
Vaxry
be3d635265 makefile: update wlroots sover 2023-11-24 13:08:58 +00:00
André Silva
f9ba5a0551 flake.lock: update nixpkgs and xdph 2023-11-24 15:06:35 +02:00
thejch
258c83f3bb exec: remove redundant environment variables from spawn (#3923) 2023-11-24 12:42:20 +00:00
vaxerski
aedcade68d opengl: better checking for required introspection
performance woo
2023-11-24 12:37:10 +00:00
vaxerski
802ab58f8a renderer: fix inverseOpaque calcs in renderWithBlur 2023-11-24 12:32:35 +00:00
Vaxry
af5d06593f cmakelists: fix old wlroots sover 2023-11-24 10:59:02 +00:00
Vaxry
2ebfd0c745 renderer: Move to a full Hyprland GL rendering pipeline (#3920)
Also updates wlroots
2023-11-24 10:54:21 +00:00
vaxerski
e40e486f61 renderer: better checks for special rendering in renderWorkspaceWindows
ref #3916 #3888
2023-11-23 11:31:52 +00:00
Vaxry
e55c5a916a renderer: make sure lastWindow has correct ws in renderWorkspaceWindows
fixes #3916 fixes #3888
2023-11-22 23:43:46 +00:00
Vaxry
45ebe0df8f config: fix red warn in default config
fixes #3917
2023-11-22 23:38:14 +00:00
Vaxry
812a3f6d78 renderer: fix double render of tiled on workspace switch
fixes #3889
2023-11-22 20:05:50 +00:00
Vaxry
44accacff9 config: add nomaximizerequest all to default cfg 2023-11-22 19:50:37 +00:00
Ngô Huy
d417370bb7 makefile: Add CXXFLAGS to hyprlctl's Makefile (#3913) 2023-11-22 11:02:36 +00:00
zakk4223
4729265284 hyprctl: Add 'layouts' command (#3895)
* Add hyprctl 'layouts' command

formatting

* Add getAllLayoutNames(), move m_vLayouts back to private

Formatting

* clang-format
2023-11-21 18:43:38 +00:00
thejch
572fd554b8 renderer: Fix floating clipbox (#3907)
* fix floating decoration clipbox scale

* use vecTransformedSize

* use workspace offset
2023-11-21 00:34:34 +00:00
thejch
7d1c8d827a shadow: add workspace offset to floating window shadow (#3906) 2023-11-20 22:34:28 +00:00
thejch
6d26199e1c renderer: fix floating window rendering when scale > 1 (#3901) 2023-11-20 12:13:09 +00:00
end-4
646f4bc638 general: add workspace gaps (#3877)
* anims: workspace gap

* anims: ws gaps: on swipe end

* anims: ws gaps: add missing parentheses

* format

* refractor

* Update Swipe.cpp

* format

* fix swipe to right

* ws gaps: move animations:workspace_gap to general:gaps_workspace

* ws gaps: general:gaps_workspace -> general:gaps_workspaces
2023-11-19 12:33:26 +00:00
MightyPlaza
7e0c90b92c groupbar: fix text pos with verical offset (#3893)
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
2023-11-19 12:29:26 +00:00
MightyPlaza
add23a9ba2 group: fix dragging into floating groups (#3719)
* allow dragging into floating groups

modified:   src/Compositor.cpp
modified:   src/Compositor.hpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* floating-only
modified:   src/layout/IHyprLayout.cpp
2023-11-19 12:29:01 +00:00
Dickby
3d89654254 vector: New operator overloads and small fix in Vector2D. (#3891) 2023-11-18 21:37:16 +00:00
Dickby
6ad5f26cfe layout: Don't update pseudoSize after window moved by mouse. (#3873) 2023-11-18 19:59:12 +00:00
Vaxry
89f6457a99 renderer: avoid rendering floating windows twice with special
fixes #3887
2023-11-18 19:53:45 +00:00
Vaxry
8b57a1973e internal: Allow floating windows on special (#3872)
* allow floating on special

* fix mistake

* fix clipbox
2023-11-18 17:00:24 +00:00
Vaxry
483302a2cd env: add HYPRLAND_NO_RT 2023-11-17 23:29:30 +00:00
Vaxry
a903dba858 cmake: include tracy cpp if set 2023-11-17 23:26:54 +00:00
Vaxry
395985f815 pluginmgr: fix double use of dlerror() 2023-11-17 22:24:52 +00:00
Vaxry
51282f964f plugins: make logging on error more verbose
ref #3874
2023-11-17 22:22:31 +00:00
TheAngusMcFire
db8f13291a hyprctl: add monitors all to report all connected monitors (#3730)
---------

Co-authored-by: Christian Rieger <christian.rieger@student.tugraz.at>
2023-11-17 16:01:21 +00:00
André Silva
30ad71ff36 nix: add libGL to build inputs 2023-11-17 17:36:18 +02:00
Vaxry
84bc0a73f6 compositor: drop unused vectorToWindow func 2023-11-17 15:30:04 +00:00
Dickby
1d9bfa60a1 opengl: Don't use wrong shader just because it's GLES (#3867) 2023-11-16 21:03:17 +00:00
Vaxry
a34e192433 renderer: clip floating boxes on slide anim
fixes #3514
2023-11-16 20:20:41 +00:00
Vaxry
4868d4dfd3 shadow: avoid fatal mutation of the windowBox for calcs
fixes #3865
2023-11-16 17:31:52 +00:00
vaxerski
859841f4d1 renderer: don't make snapshots of invisible windows on close 2023-11-16 12:24:07 +00:00
vaxerski
28ef18a921 shadow: avoid using glClear and don't draw behind window if ignore_window
fixes #3860
2023-11-16 11:42:53 +00:00
Dickby
91d6be1f09 groupbar: Fix position of groupbar titles on monitor scales != 1.0 (#3856) 2023-11-15 20:32:44 +00:00
thejch
9e3dccca76 keybinds: Close special workspace after moving windows out of it (#3649)
* use old monitor

* use pMonitor for for special workspace
2023-11-15 12:32:02 +00:00
Vaxry
81598b3dbd README: update showcase 2023-11-14 20:08:00 +00:00
Vaxry
e195e51c1b logging: move to an internal rolling log buffer
disables logging to the logfile by default
2023-11-14 20:06:04 +00:00
Vaxry
e8469f8b1b renderer: drop unnecessary spammy logs 2023-11-14 19:51:47 +00:00
Vaxry
49597688e9 windowrules: make idleinhibit dynamic 2023-11-14 15:46:57 +00:00
Vaxry
5edb4e4a30 decorations: recalc layout and positioner on add/remove 2023-11-13 16:42:58 +00:00
Ching Pei Yang
4d6fa6ed0c pluginapi: add touch event hooks (#3836) 2023-11-13 16:32:12 +00:00
Vaxry
016a7a9c9b hyprctl: use a rolling buffer for reading requests
fixes #3846
2023-11-13 16:30:37 +00:00
Vaxry
2e26542e3b renderer: use viewporter corrected size for uv calcs 2023-11-12 23:57:53 +00:00
Vaxry
68935ba9dc renderer: separate oversize uv calcs in dimensions 2023-11-12 23:27:52 +00:00
Vaxry
ba5bc5871f subsurfaces: damage window on subsurface size change 2023-11-12 23:06:31 +00:00
Vaxry
824ccd957b renderer: pass proper arg to main param of uv calcs
was fucking up some non-fitting subsurfaces
2023-11-12 22:59:19 +00:00
Vaxry
45e86d4fdf groupbar: translate box by workspace offset 2023-11-12 22:40:21 +00:00
Vaxry
0ba2e68704 deco-positioner: don't remove hidden windows' data 2023-11-12 17:02:42 +00:00
Dickby
e974d1fe98 shaders: Some more changes in rgb2hsl. (#3834) 2023-11-12 16:20:23 +00:00
Vaxry
47d46aa56c inputmgr: clean lists in ~dtor
ref #3558
2023-11-12 14:03:46 +00:00
Vaxry
65efde32c9 internal: make getPlusMinusKeywordResult return optional 2023-11-12 13:40:02 +00:00
Vaxry
69e314207d internal: replace INT_MAX with WORKSPACE_INVALID 2023-11-12 13:34:54 +00:00
Alessio Molinari
1bfd4a2bff output-layout: fix wlroots display handling (#3718) 2023-11-12 13:14:05 +00:00
Vaxry
91cbe93cf8 decoration: add NON_SOLID flag for shadow
fixes #3841
2023-11-12 13:01:23 +00:00
Vaxry
9afdd61ade props: bump ver to 0.32.3 2023-11-11 18:14:46 +00:00
Vaxry
f39a6ca17c decoration-positioner: improve stability 2023-11-11 18:07:56 +00:00
Vaxry
eab2799842 props: bump ver to 0.32.2 2023-11-11 17:24:04 +00:00
Dickby
6eb2abcb20 shaders: Small optimization in rgb2hsl. (#3831) 2023-11-11 17:20:18 +00:00
Vaxry
ae46fbafe5 xdg: set state maximized for all tiled windows
forces them to not draw stupid decorations of their own. Wlroots stopped doing it for us. Fixes #3830
2023-11-11 17:13:20 +00:00
Vaxry
52cf122a0a shadow: move workspace offset calcs to draw
fixes #3829
2023-11-11 16:15:23 +00:00
Dickby
844da8db56 shaders: Avoid calculating unused values in hsl2rgb. (#3827) 2023-11-11 15:43:31 +00:00
Vaxry
db82fc5b09 animationmgr: push shadow avs to ended on disabled 2023-11-11 15:23:33 +00:00
Vaxry
8180ca65a5 props: bump ver to 0.32.1 2023-11-11 15:20:21 +00:00
Vaxry
bea828ea45 decoration-positioner: improve extent handling 2023-11-11 15:18:17 +00:00
vaxerski
c5d1faf72d [gha] Nix: update wlroots 2023-11-11 14:53:18 +00:00
Vaxry
cc04b52ce1 deco-positioner: recalc after uncache 2023-11-11 14:52:27 +00:00
Vaxry
9b5e2e71e0 deps: update wlroots 2023-11-11 14:47:25 +00:00
Vaxry
9be6fbf5ea decorations: Decoration Positioner (#3800) 2023-11-11 14:37:17 +00:00
Dickby
7345b1a1ea shaders: Use clamp in doubleCircleSigmoid. (#3824) 2023-11-11 13:15:37 +00:00
Vaxry
e44d6de555 shadow: alpha treatment improvements 2023-11-11 00:52:40 +00:00
Vaxry
427153e86a xwayland: add half of delta to configure request sizes 2023-11-10 23:49:35 +00:00
Greatly Pleased
1e6e9b66a5 hyprctl: Fix build warnings (#3821) 2023-11-10 21:45:20 +00:00
Vaxry
92cb44ddb2 input: don't schedule repaint on cursor move if hardware cursors are in use 2023-11-10 18:49:15 +00:00
Vaxry
b8a615ffb8 xdg-shell: improve ack-configure handling
fixes #3807
2023-11-10 00:13:22 +00:00
Vaxry
8dd02eb5f3 xdg-shell: update reported size on ack_configure 2023-11-09 22:43:52 +00:00
Vaxry
14195835ef opengl: switch to black-and-white for alpha mattes
also fixes shadows on 10b
2023-11-09 22:11:54 +00:00
Vaxry
11432f69b9 opengl: remove unused alpha matte from shadow 2023-11-09 22:11:54 +00:00
Tobias Pisani
da6fa9cbd2 hyprctl: return group list in correct order (#3683) 2023-11-09 16:05:05 +00:00
Vaxry
c619e6976f screencopy: round boxes
fixes #3795
2023-11-08 12:43:07 +00:00
Vaxry
751d2851cc props: bump ver to 0.32.0 2023-11-07 21:06:38 +00:00
Vaxry
a0fcda301d layout: round box in mouseMove
fixes #3792
2023-11-07 20:47:09 +00:00
Vaxry
47654a84c2 main: set isShuttingDown after display dispatch reaches the end
relates to #3558
2023-11-07 14:53:56 +00:00
Visual-Dawg
29e0a7112e renderer: added new customization options to the blur shaders (#3650)
Adds to `decoration:blur:` `vibrancy` and `vibrancy_darkness`
2023-11-06 18:49:03 +00:00
Vaxry
a1b7a5a53d layout: fix various rounding errors
maybe finally will end #3761
2023-11-06 17:00:37 +00:00
Vaxry
ecf98069f6 layout: round window boxes after special scale factor
fixes #3761 again
2023-11-05 19:57:23 +00:00
David Leal
0476e1b498 groups: add option to configure font name (#3751) 2023-11-05 19:25:50 +00:00
Brett Alcox
a122271f09 includes: fix box headers (#3771) 2023-11-05 17:32:27 +00:00
Vaxry
600a128f83 compositor: allow windowfromregex tiled param 2023-11-05 16:22:43 +00:00
Vaxry
55825c301e compositor: allow windowfromregex floating param
fixes #3766
2023-11-05 16:21:47 +00:00
Vaxry
d8b7ded18c compositor: find windows in direction on floating 2023-11-05 16:18:41 +00:00
Vaxry
c4e1a9b13b box: use std::round instead of std::floor in ::round()
fixes #3761, possibly also #3511
2023-11-05 14:47:24 +00:00
Vaxry
9404972732 events: set reported size on floating map
fixes #3767
2023-11-05 14:12:55 +00:00
Vaxry
3b786419d8 subprojects: update tracy 2023-11-05 00:32:22 +00:00
Vaxry
92e535025e region: include box in the header 2023-11-04 23:12:08 +00:00
Vaxry
d3e5796ee1 layout: fix missed setWindowSize in no_gaps_when_only node apply
fixes #3758
2023-11-04 23:00:20 +00:00
Vaxry
56dec1c6a2 renderer: properly set currentFB on snapshot renders 2023-11-04 22:25:09 +00:00
Vaxry
931927de29 dwindle: move to CBox for expressing nodes 2023-11-04 21:45:34 +00:00
Vaxry
74cf2281dd binds: add movefocus_cycles_fullscreen
fixes #3738
2023-11-04 21:03:08 +00:00
Vaxry
2b07d54bc7 shadow: fix missed fullBox.scale 2023-11-04 20:11:22 +00:00
Vaxry
66a3719b86 renderer: allow transform enabling from outside opengl 2023-11-04 19:35:49 +00:00
Vaxry
64a084477e shadows: fix on transformed 2023-11-04 19:32:50 +00:00
Vaxry
7a09d24065 shadow: fix ignore_window false 2023-11-04 17:45:31 +00:00
Vaxry
a3e20d2d5f wlsurface: fix small detection 2023-11-04 17:39:56 +00:00
Vaxry
32b3d2b456 includes: include vector2d for sharedDefs 2023-11-04 17:27:21 +00:00
Vaxry
447c173cad includes: include sharedDefs in includes.hpp 2023-11-04 17:04:10 +00:00
Vaxry
55b4f84fea Internal: Hyprland box implementation (#3755)
* box impl

* remove unused operators

* missed applyfromwlr
2023-11-04 17:03:05 +00:00
Vaxry
73e78f05ad Decos: Window decoration flags, shadow improvements (#3739) 2023-11-04 13:10:52 +00:00
Vaxry
54e51b7acf events: better adjust to unreported sizes for xwayland apps
fixes #3745
2023-11-04 13:09:33 +00:00
Vaxry
200cccdd3b events: set reported size on the end of mapping
fixes #3743
2023-11-03 22:47:12 +00:00
Vaxry
15b25d5850 renderer: render oversized blur with respect to fade alpha 2023-11-03 21:58:02 +00:00
Vaxry
21ba8b363e fractional-scale: fix addon existence check 2023-11-03 21:02:12 +00:00
Vaxry
9d2a5fb417 renderer: improvements to wayland surface small() detection 2023-11-03 19:12:09 +00:00
thejch
ed3d5053b2 Master: fix drop_at_cursor when there are only two windows (#3734)
* make drop_at_cursor work when dragging into a one-window workspace

* fix drop_at_cursor when new_is_master is enabled
2023-11-03 17:02:59 +00:00
Vaxry
93a2ac9de4 fractional-scale: post error on taken fs objects
fixes #3735
2023-11-03 15:51:43 +00:00
pastalian
49fdffacea renderer: fix legacy_renderer build (#3732)
In GLES2, `GL_RGB10_A2` and `GL_UNSIGNED_INT_2_10_10_10_REV` are defined as
`GL_RGB10_A2_EXT` and `GL_UNSIGNED_INT_2_10_10_10_REV_EXT` respectively.
2023-11-03 15:47:20 +00:00
vaxerski
0f6e530798 layout: better storage for no fullscreen checks var
fixes #3731
2023-11-03 12:19:23 +00:00
Vaxry
88b47dfa83 xdg: use std::ceil for sending scale to surfaces
fixes #3724
2023-11-02 23:29:47 +00:00
Vaxry
ba9e7814b0 input: simulate movement only if mouse is over in open/close window
fixes #3726
2023-11-02 21:36:16 +00:00
thejch
f10996b575 master: fix moving window between monitors (#3721) 2023-11-02 17:20:32 +00:00
q234rty
ef90d1eaaf Map cmake None to meson's plain
empty is not a build type that exists in meson.

I have no idea why I typed "empty" in #3614 ...

Fixes: ba5f1d8783
2023-11-02 19:20:09 +02:00
Dashie
062f749450 xdg: send unconstrain events after a popup reposition (#3716)
* fix: Use unconstrain_from_box after reposition request

* chore: Remove unused include

* chore: remove variable specifier
2023-11-01 20:31:52 +00:00
Vaxry
a4db48b46b input: simulate mouse movement to fix focus on open/close window
fixes #3679
2023-11-01 19:50:32 +00:00
MightyPlaza
c44e255194 group: fixes for dragging groups onto groupbars (#3708)
* fixes for dragging groups onto groupbars

modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* use onWindowRemoved()
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
2023-11-01 19:13:39 +00:00
Vaxry
21e9313c10 Core: various unsafe state improvements (#3713)
Fixes #3637
2023-11-01 18:53:36 +00:00
Vaxry
7b32b4214d layout: avoid redundant size sets on new fullscreen 2023-11-01 01:28:43 +00:00
Vaxry
6914103289 cmake: set asan for only hyprland not others 2023-10-31 21:45:27 +00:00
Vaxry
ab5497a0c9 input: properly track xdg surfaces' geometry in vectorToSurfaceLocal
fixes #3703
2023-10-30 19:36:45 +00:00
André Silva
f48b3774a2 nix: use mesonAutoFeatures attribute 2023-10-30 21:00:04 +02:00
Vaxry
1c9d6b94d1 renderer: fix small surface's blur region being offset by monitor coords 2023-10-30 16:20:30 +00:00
Vaxry
4b592d0819 renderer: properly pass 10-bit formats to opengl 2023-10-30 15:56:16 +00:00
MightyPlaza
a1924ae435 internal: create canBeGroupedInto() (#3693)
modified:   src/Window.cpp
modified:   src/Window.hpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
2023-10-30 14:54:12 +00:00
Vaxry
cb6cfde6e8 window: update window reported size on damage events 2023-10-30 14:49:49 +00:00
Vaxry
8e91c038db renderer: use optional for cursor surface storing
because nullptr is a valid surface.

fixes #3692
2023-10-30 00:18:40 +00:00
Vaxry
86318ce04f input: let input-grabbing decos have prio over resize on border 2023-10-29 23:37:12 +00:00
Vaxry
59d6a12a7e config: fixup usage of plugin in handles
would filter calls to keyword plugin: and stuff
2023-10-29 22:35:26 +00:00
Vaxry
935c90915a pluginapi: fixup get_hash functions 2023-10-29 21:21:54 +00:00
Vaxry
b95c0c318e renderer: fixup blend disable conditions in renderSurface
Fixes #3680
2023-10-29 20:54:14 +00:00
MightyPlaza
9abfa9efc6 input: handle mouse on decorations (#3560) 2023-10-29 20:14:47 +00:00
Vaxry
7a5234a0cc input: better cursor image infrastructure
Improves handling of cursor images/surfaces
Fixes an issue with decos and cursors
Fixes #3471
2023-10-29 18:09:05 +00:00
Vaxry
af9440152e pluginapi: add a config keyword adding method 2023-10-29 16:59:50 +00:00
Vaxry
7f4b0aaadc hyprctl: add focusHistoryID to hyprctl clients
fixes #3661
2023-10-28 17:22:42 +01:00
vaxerski
4a4e13f8ac events: ignore takes_over_fullscreen for floating windows
fixes #3622. Floating windows should not respect the config option, they should be shown on top. That option is meant for tiled only
2023-10-27 12:45:17 +01:00
Antoine Dutot
1d47e2c408 input: fix force_zero_scaling for tablet and touch (#3644)
* Attempt to fix force_zero_scaling for tablet and touch for XWayland apps.

* Formated using clang-format.

* Simpler way to compute touch origin.
2023-10-27 10:15:29 +01:00
Vaxry
47256a6ed8 input: remove incorrect check in re-enter
fixes #3659
2023-10-26 22:21:13 +01:00
Vaxry
732b058489 input: send motion events on focusWindow if follows_mouse is 0 2023-10-26 22:17:49 +01:00
Vaxry
92cf1c2337 input: fix mouse down handling on unset last surface
fixes #3659
2023-10-26 18:54:19 +01:00
Tyler Schneider
07714dd5bd input: Apply scaling to cursorPosOnActivate position (#3664) 2023-10-26 02:05:10 +01:00
fufexan
5cc33b4e8c [gha] Nix: update inputs 2023-10-26 00:03:23 +00:00
Vaxry
b0b88a63b6 renderer: fix missed box scale 2023-10-25 22:38:14 +01:00
Vaxry
5b0dc779ed renderer: blur properly behind small surfaces 2023-10-25 22:20:58 +01:00
Vaxry
8991be671f renderer: respect viewporter dest on base surfaces 2023-10-25 22:05:04 +01:00
Vaxry
6650e4ba85 compositor: remove old comment 2023-10-25 18:32:04 +01:00
vaxerski
a1b138a625 [gha] Nix: update wlroots 2023-10-24 23:28:24 +00:00
Vaxry
df00727310 deps: update wlroots 2023-10-25 00:27:16 +01:00
Vaxry
03771d3aa9 windowrules: add nearestneighbor 2023-10-24 21:29:03 +01:00
André Silva
50a80efad5 flake.lock: update nixpkgs and xdph 2023-10-24 21:06:00 +03:00
Vaxry
14a3c939ce hyprctl: log monitor id in workspaces request
fixes #3640
2023-10-24 01:03:40 +01:00
Vaxry
aeb8c8fc70 internal: honor close_special_on_empty on moveToWorkspace
fixes #3602
2023-10-24 00:58:44 +01:00
Vaxry
616ff343b7 input: fix warn 2023-10-24 00:53:59 +01:00
Vaxry
2f6729f557 example: add special workspace to default config 2023-10-24 00:50:45 +01:00
Vaxry
015664eb4c compositor: do not process fullscreen events in unsafe 2023-10-23 00:53:33 +01:00
Vaxry
98059b52d7 layershell: support ON_DEMAND keyboard mode
fixes #2264
2023-10-22 23:32:55 +01:00
Brenno Lemos
b135bd6cd4 workspacerules: Add new optional "default command" for auto-launching apps on new workspaces (#3559) 2023-10-22 23:11:03 +01:00
Vaxry
59f27e7f57 compositor: send preferred scale and transform events to surfaces
fixes #3635
2023-10-22 16:58:06 +01:00
Vaxry
edb26e0306 cmake: remove old definitions from cmakelists 2023-10-22 12:25:26 +01:00
Vaxry
d0367d8560 renderer: use preOffset pos instead of offset
offset is not passed to transformers, so if they change pos, decos will be in the wrong place
2023-10-21 19:51:14 +01:00
Vaxry
95db9108e5 transformers: allow modifying renderdata pre-pass 2023-10-21 19:25:44 +01:00
Vaxry
a61eb7694d hooksystem: add callbackinfo struct and cancellable events 2023-10-21 14:52:43 +01:00
Vaxry
c6233a790f renderer: avoid drawing invisibly small surfaces in renderSurface 2023-10-21 14:20:06 +01:00
Vaxry
92311d260a renderer: add transformers 2023-10-21 14:15:56 +01:00
Roberto Previdi
af72404259 hyprctl: add a query for workspace rules (#3630) 2023-10-21 02:28:34 +01:00
Vaxry
4a79718fe8 renderer: fix shimmers when manual resizing 2023-10-20 20:32:47 +01:00
Vaxry
7f35f33b4c surface/wayland: conform to small surface requirements
do not stretch small surfaces, instead center them if they fit.
2023-10-20 20:15:57 +01:00
thejch
bab2f6a664 master: fix movewindow across monitors (#3628) 2023-10-20 18:01:04 +01:00
thejch
bb9d0aed5b compositor: Fix a lack of a check for workspace equality on same monitors in getInDirection (#3625)
* prevent movefocus and movewindow from going into main workspace when in special workspace

* compare workspace IDs instead

* change comparison and make code more readable
2023-10-20 10:53:37 +01:00
Vaxry
386708563c workspacerules: search for special properly
fixes #3537
2023-10-19 16:04:59 +01:00
q234rty
ba5f1d8783 cmake: Map cmake None to meson empty (#3614)
While not explicitly mentioned by the cmake documentation, cmake
upstream seems to think of None as a vaild CMAKE_BUILD_TYPE. [1]
Handle it properly by mapping it to meson's empty.

[1]: ce1cadd35a
2023-10-19 15:59:24 +01:00
Campbell Barton
d994e6aea6 cmake: Fix error building without CMAKE_BUILD_TYPE being set (#3590)
* Fix error building without CMAKE_BUILD_TYPE being set

This resolves the error building without a CMAKE_BUILD_TYPE.
CMake Error at CMakeLists.txt:36 (string):                                                                                                                                                          
  string no output variable specified

* CMake: convert CMake's build type to meson build type

Fix error when the CMAKE_BUILD_TYPE variable isn't set & properly convert the build type to mesons build type.
2023-10-19 15:00:58 +01:00
Vaxry
6e15590e98 shaders: support changing the outer radius of borders independently 2023-10-19 14:05:02 +01:00
memchr
d70cc88dab meson: generate version.h before install_headers (#3612)
Otherwise, meson install would not install version.h as a header in a
clean build.
2023-10-19 00:09:06 +01:00
Vaxry
a0b675ec9e binds: add ignoreMods flag 2023-10-17 20:10:07 +01:00
André Silva
784f8a88fb input: don't reset cursor movement timer on simulateMouseMovement (#3595)
Fixes #2570
2023-10-17 17:00:39 +01:00
thejch
20e7ccd480 master: fix resizing wrong window behind in special workspace (#3591) 2023-10-17 12:06:16 +01:00
outfoxxed
210be10c92 meson/nix: Fix meson.build nix patch (#3594)
`meson.build` was modified in #3547 but `nix/patches/meson-build.patch`
was not updated to reflect the changes.
2023-10-17 12:05:38 +01:00
eriedaberrie
421f5fb221 events: make new windows taking over fullscreen keep the existing mode (#3588) 2023-10-17 11:41:27 +01:00
Jan Beich
93676f91a0 renderer: cast std::clamp args to be of the same type (#3589)
src/render/OpenGL.cpp:1769:41: error: no matching function for call to 'clamp'
    const auto         FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, -1L, 2L);
                                        ^~~~~~~~~~
/usr/include/c++/v1/__algorithm/clamp.h:38:1: note: candidate template ignored: deduced conflicting types for parameter '_Tp' ('int64_t' (aka 'long long') vs. 'long')
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi)
^
/usr/include/c++/v1/__algorithm/clamp.h:27:1: note: candidate function template not viable: requires 4 arguments, but 3 were provided
clamp(const _Tp& __v, const _Tp& __lo, const _Tp& __hi, _Compare __comp)
^
2023-10-17 01:29:06 +01:00
memchr
54e1c2ccbd fix(build): do not include wlr headers directly, use includes.hpp instead. (#3587) 2023-10-16 17:39:12 +01:00
Vaxry
5b8cfdf2ef props: bump ver to v0.31.0 2023-10-16 17:17:00 +01:00
Vaxry
8af3e7beeb cmake: search for systemd headers first 2023-10-15 22:35:56 +01:00
Alexander Seleznev
1f582457cf Debug: respect logging settings for wlr (#3584) 2023-10-15 19:19:07 +01:00
Philip Damianik
442209942f cleanup: Replace find() with C++20 starts_with(), ends_with() and contains() (#3572)
* Replace find() with C++20 starts_with() and ends_with()

* Replace find() with C++20 contains()
2023-10-15 19:07:23 +01:00
memchr
43b39e0bc6 build: include version.h in PluginAPI.hpp (#3571) 2023-10-15 12:22:51 +01:00
Ali Rizvi
261c594458 makefile: fix using -d test for a binary file AND re-add missing portals conf (#3570)
* fix: Makefile test
modified: src/Makefile

* add: hyprland-portals.conf cp to Makefile
modified: src/Makefile
2023-10-14 22:30:17 +01:00
memchr
962a0de01a meson: use ln with force flag (#3568) 2023-10-14 20:59:11 +01:00
Vaxry
21b5cf402a makefile: warn users when doing sudo make install 2023-10-14 18:58:23 +01:00
Vaxry
d4e4931008 build: CMake pipeline improvements (#3564) 2023-10-14 18:48:05 +01:00
Vaxry
d5a572bd39 Plugin API: Add version query (#3545) 2023-10-14 18:47:43 +01:00
Vaxry
424c9a7e70 render: stop locking SWC on tearing 2023-10-13 22:11:21 +01:00
Michał Lewandowski
3a61350286 notifications: Schedule a frame on notification creation (#3556) 2023-10-13 00:05:05 +01:00
vaxerski
e4bcd2e2da monitor: ensure vrr on workspace change 2023-10-12 17:26:35 +01:00
Vaxry
06cc42441c build: guard execinfo.h via build systems (#3547)
* guard execinfo via cmake

* libexecinfo -> execinfo macro name

* meson: add execinfo check

* move check in cmake up

---------

Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
2023-10-11 22:27:53 +01:00
Bernhard M. Wiedemann
5dc7161b1d meson: Sort input file list (#3550)
so that hyprland builds in a reproducible way
in spite of non-deterministic filesystem readdir order.

See https://reproducible-builds.org/ for why this is good.
This patch was done while working on reproducible builds for openSUSE.

Co-authored-by: Bernhard M. Wiedemann <bernhard+gitcommit lsmod.de>
2023-10-11 19:49:42 +01:00
Jan Beich
0cf3d5b39a build: Unbreak Meson build on FreeBSD (#3549)
* generateVersion.sh: move cp(1) flags before arguments

POSIX and BSD cp(1) don't support flags after arguments e.g.,

cp: -fr is not a directory

* generateVersion.sh: switch to sed(1) -i for better compatibility

On BSDs awk is usually The One True Awk thus doesn't support `-i inplace`.

awk: unknown option -i ignored
awk: can't open file {sub(/@HASH@/,"1234567890abcdef")}1
 source line number 1
2023-10-11 19:38:34 +01:00
memchr
34455844e9 groups: ensure consistency in dispatcher behavior with global group lock (#3531) 2023-10-11 11:13:12 +01:00
vaxerski
d83357f497 internal: use pragma once in version.h 2023-10-10 21:03:07 +01:00
Mihai Fufezan
a0038fa161 CI/release: update version generation 2023-10-10 22:53:23 +03:00
Vaxry
914851b91a internal: better versioning (#3543)
* better versioning

* meson: better versioning

* nix: better versioning

---------

Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
2023-10-10 20:21:57 +01:00
vaxerski
3219c84433 makefile: set perms for built subprojects in pluginenv 2023-10-10 20:03:02 +01:00
vaxerski
1a0909aa20 makefile: set 777 for /build perms 2023-10-10 20:01:02 +01:00
vaxerski
bf94df7b00 makefile: set correct perms on includes 2023-10-10 19:59:42 +01:00
MightyPlaza
d537815d43 groups: create group and groupbar config sections (#3522)
* config: create group section

modified:   src/Compositor.cpp
modified:   src/config/ConfigManager.cpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/input/InputManager.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* separate group border and groupbar colors

modified:   src/Compositor.cpp
modified:   src/config/ConfigManager.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* add new line
modified:   config/ConfigManager.cpp
2023-10-10 17:42:45 +01:00
Philip Damianik
ac1bd47653 dispatchers: Add option to center the cursor on the focused window when switching workspaces (#3528)
* Add option for centering on workspace when switching workspace

* Add option for centering on workspace when switching workspace

---------

Co-authored-by: vaxerski <43317083+vaxerski@users.noreply.github.com>
2023-10-10 17:34:28 +01:00
vaxerski
8abb6e1cee screencopy: enhance error logging 2023-10-09 23:51:59 +01:00
Roberto Previdi
df0c8e0f7a workspacerules: Add a persistent workspace rule (#3530)
* add persistent flag to workspace rules

* get rid of unused ws->indestructible flag
2023-10-09 20:28:22 +01:00
Michał Lewandowski
7f8e0a1318 dwindle: Avoid rounding errors in window position (#3524)
* Avoid rounding errors in window position

* Fix naming scheme

* Fix unwanted window movement
2023-10-09 12:28:58 +01:00
MightyPlaza
499df49f7b dispatchers: fix extra monitor offset when snapping floating (#3520)
modified:   src/managers/KeybindManager.cpp
2023-10-08 13:49:15 +01:00
vaxerski
728a8bb48e config: mention force_default_wallpaper in default configs 2023-10-07 15:55:33 +01:00
DaniD3v
7d7565e7ec renderer: add force_wallpaper instead of no_hypr_chan (#3459) 2023-10-07 14:08:38 +01:00
vaxerski
38e242953d animationmgr: damage floating windows on workspace anim
fixes #3514
2023-10-07 02:28:23 +01:00
Jeremy Huang
61d3d4dee7 master: fix drop_at_cursor on workspace 2 (#3512) 2023-10-06 22:33:11 +01:00
ItsDrike
1afb00a01b pluginapi: remove starting newline in demangled func name (#3502) 2023-10-06 14:01:40 +01:00
vaxerski
cb7dd1ac6e layershell: avoid configure on unchanged size
fixes #3496
2023-10-06 14:00:05 +01:00
vaxerski
4b3efc73c5 events: fixup empty events not being sent on unmap
Ref #3506 https://github.com/hyprwm/Hyprland/issues/3506#issuecomment-1749508111
2023-10-06 01:11:47 +01:00
vaxerski
24c04a8b7c crashreporter: avoid using empty CACHE_HOME 2023-10-05 16:57:54 +01:00
vaxerski
3d1a167960 wsrules: check for workspace ID matches on numbered workspaces
fixes #3494
2023-10-05 01:31:13 +01:00
vaxerski
1b99a69dc1 [gha] Nix: update wlroots 2023-10-04 14:06:09 +00:00
vaxerski
8e0eafc502 deps: update wlroots 2023-10-04 15:05:20 +01:00
vaxerski
e689b1ba11 [gha] Nix: update wlroots 2023-10-04 14:01:11 +00:00
vaxerski
322c5cc4b9 layout: add new_window_takes_over_fullscreen mode 2
fixes #3486
2023-10-04 15:00:24 +01:00
vaxerski
230356012b renderer: extract solitary check into frame handler 2023-10-04 13:48:44 +01:00
vaxerski
4531717f3e renderer: considerable fixes to repaint logic 2023-10-04 13:39:40 +01:00
vaxerski
f8c18ff797 renderer: fixup solitary conditions 2023-10-04 13:30:13 +01:00
vaxerski
f803be3d31 input: fixup frame schedule conditions on mouse move 2023-10-04 12:57:37 +01:00
vaxerski
2901bb0d2f renderer: add further conditions to solitary recheck 2023-10-04 09:44:07 +01:00
Jeremy Huang
d61e4f9ad7 master: add option to drag and drop windows at cursor position (#3465)
* add option to drag and drop a window at cursor position

* use getWindowIdealBoundingBoxIgnoreReserved
2023-10-03 22:16:57 +01:00
vaxerski
b784931e67 [gha] Nix: update wlroots 2023-10-02 15:48:58 +00:00
vaxerski
fcab2a4358 deps: update wlroots 2023-10-02 16:47:54 +01:00
vaxerski
b814ba98a7 misc: add misc:new_window_takes_over_fullscreen
referenced in #3474
2023-10-02 16:27:32 +01:00
vaxerski
50fecf084d events: set new window alpha to 0 if it's tiled behind fullscreen
fixes #3474
2023-10-02 16:22:39 +01:00
vaxerski
5ffb1032e1 events: don't focus new window if spawned behind fullscreen
fixes #3473
2023-10-02 14:09:23 +01:00
vaxerski
fc1d7acd9a renderer: fix missing check for surfaceCount in rechecking solitary
closes #3470
2023-10-02 14:02:19 +01:00
gnusenpai
778bdf730f internal: Add GTK portal as fallback (#3469)
needed for XDP 1.17+ since the fallback to the GTK portal was removed
2023-10-02 10:51:15 +01:00
vaxerski
763bb2d3bc renderer: remove old debug log 2023-10-02 10:50:33 +01:00
vaxerski
9ec656a37d makefile: make binaries 755 instead of 711
fixes #3466
2023-10-01 14:09:50 +01:00
memchr
161fee1d82 internal: include missing header (#3464) 2023-10-01 12:26:10 +01:00
vaxerski
a2a29a60e5 tearing: cleanup vars and avoid rendering before drm is ready 2023-09-30 17:07:50 +01:00
vaxerski
e2b72b2975 renderer: avoid spamming software cursor locks 2023-09-30 16:55:41 +01:00
Dickby
772c7d1d3c shaders: Remove redundant clamp of smoothsteps return value. (#3456) 2023-09-30 13:12:48 +01:00
vaxerski
6a4643842d hyprctl: log activelyTearing for monitors 2023-09-30 13:12:04 +01:00
vaxerski
a05076a7ee log: log wlr errors regardless of env 2023-09-30 13:12:04 +01:00
vaxerski
b8f8912db2 renderer: lock software cursors while tearing 2023-09-30 13:12:01 +01:00
vaxerski
86e8ed038f includes: add missing log include to animatedvariable 2023-09-30 02:09:08 +01:00
vaxerski
c298439433 renderer: nuke multisample_edges in favor of a faster algorithm 2023-09-30 01:41:05 +01:00
vaxerski
495d4f2d11 shaders: improve border rounding 2023-09-30 01:35:05 +01:00
vaxerski
7b002d609b input: fix warn 2023-09-29 20:06:20 +01:00
vaxerski
4daa515700 watchdog: don't hang on exit 2023-09-29 20:05:43 +01:00
vaxerski
e07e64458e input: fix unused variable warn 2023-09-29 17:55:41 +01:00
vaxerski
a44ab7748f renderer: optimize render pipeline when there is a solitary client 2023-09-29 17:51:07 +01:00
vaxerski
ab11bd2085 watchdog: remove thread on destroy 2023-09-29 17:33:26 +01:00
vaxerski
27cd7ef0c9 watchdog: initialize after config 2023-09-29 17:04:20 +01:00
vaxerski
9cc614d096 internal: add a watchdog
a watchdog will abort processing a signal if a timeout specified via debug:watchdog_timeout is reached.
2023-09-29 16:38:13 +01:00
vaxerski
3f09b14381 makefile: fixup permissions on installed binaries 2023-09-28 22:13:21 +01:00
vaxerski
453128ee0e examples/readme: mention tearing 2023-09-28 22:09:14 +01:00
Vaxry
88b63a00b6 renderer: Tearing implementation (#3441) 2023-09-28 21:48:33 +01:00
vaxerski
1e513e25d5 makefile: fix wrong path in chmod 2023-09-28 20:10:21 +01:00
vaxerski
d48c11cc3f input: minor constraint fixes
Better adjust to constraints that do not set a hint. Fixes #3436
2023-09-28 20:02:00 +01:00
vaxerski
08595f839b [gha] Nix: update wlroots 2023-09-28 17:06:54 +00:00
vaxerski
eab5967ef4 deps: update wlroots 2023-09-28 18:06:07 +01:00
vaxerski
280f385cf8 makefile: fix permissions on files 2023-09-28 18:05:55 +01:00
vaxerski
1f4eab176e layout: don't discard fullscreen on new tiling 2023-09-28 17:49:40 +01:00
Cascade aka. Isoheptane
6d7dc70f66 input: Add map to region options for tablets (#3425)
* Add region remap for tablets

* Fix code style
2023-09-27 19:49:30 +01:00
vaxerski
ffacd2efd1 hyprctl: fix crash in unsafe state with activeworkspace
fixes #3419
2023-09-25 15:00:28 +01:00
vaxerski
3b657257ec layout: check for specialworkspace in floating toggle 2023-09-24 23:20:15 +01:00
Legorel
6bdc45e9ce config: restore configCurrenPath after sourcing file (#3339) 2023-09-24 23:11:34 +01:00
Vaxry
46d66f4bcc internal: Further unsafe state improvements (#3404)
Instead of allowing Hyprland to sit in a state where there are no monitors, which various parts of the code don't like, we create a fake headless output on all monitor disconnect, and then remove it when a monitor appears
2023-09-24 18:04:38 +01:00
vaxerski
352ceb1117 config: trim spaces in the rule field in windowrulev2 2023-09-24 13:35:36 +01:00
vaxerski
2c4a06eb54 deps: update hyprland-protocols 2023-09-23 20:01:43 +01:00
vaxerski
3b445ec849 input: avoid using the wrong surface in drag focus force 2023-09-23 17:20:39 +01:00
memchr
8252957392 dispatchers: support number as arg in changegroupactive (#3329) 2023-09-23 13:36:40 +01:00
Jan Beich
8637bfb1b7 build: Unbreak build without precompiled headers (#3400)
* helpers: add missing header after 2e34548aea

src/helpers/VarList.cpp: In constructor 'CVarList::CVarList(const std::string&, size_t, char, bool)':
src/helpers/VarList.cpp:19:34: error: 'removeBeginEndSpacesTabs' was not declared in this scope
   19 |             m_vArgs.emplace_back(removeBeginEndSpacesTabs(in.substr(pos)));
      |                                  ^~~~~~~~~~~~~~~~~~~~~~~~
src/helpers/VarList.cpp:23:30: error: 'removeBeginEndSpacesTabs' was not declared in this scope
   23 |         m_vArgs.emplace_back(removeBeginEndSpacesTabs(std::string_view{s}.data()));
      |                              ^~~~~~~~~~~~~~~~~~~~~~~~

* helpers: add missing C linkage after 0dbd997003

ld.lld: error: undefined symbol: wlr_region_scale(pixman_region32*, pixman_region32 const*, float)
>>> referenced by Region.cpp
>>>               src/Hyprland.p/helpers_Region.cpp.o:(CRegion::scale(float))
>>> did you mean: extern "C" wlr_region_scale
>>> defined in: /usr/lib/libwlroots.so.12032
2023-09-23 13:31:37 +01:00
vaxerski
de95089552 input: fixup mouse down refocus conditions
fixes #3402
2023-09-23 13:30:53 +01:00
vaxerski
9c00381dfc hyprctl: avoid .pop_back() on empty string 2023-09-23 13:26:35 +01:00
vaxerski
fb80cbe415 input: properly track mouse focus on drag operations 2023-09-23 01:28:45 +01:00
vaxerski
1b48642fd1 props: bump version to 0.30.0 2023-09-23 00:07:52 +01:00
vaxerski
3b1e09e5a1 renderer: fix missing dontRound check in renderSurface
fixes 3296
2023-09-23 00:06:48 +01:00
vaxerski
9f68aa33ea renderer: damage monitor on special workspace change
fixes #3396
2023-09-22 23:36:28 +01:00
vaxerski
ea45bfb63c renderer: cleanup drm format selection 2023-09-22 20:15:12 +01:00
memchr
ea5d9584da refactor: manually resets singletons (#3395) 2023-09-22 11:06:09 +01:00
memchr
1357b66091 windowrules: add rule group to map windows grouped (#3279)
* windows: add rule group to map windows grouped

* group rule: use `invade` to force open a window in a locked group
2023-09-22 00:42:00 +01:00
vaxerski
2e1842b5ff screencopy: log renderer_begin_with_buffer failures 2023-09-22 00:21:07 +01:00
vaxerski
b662215fad input: simplify fullscreen workspace input calculations
Fixes an issue with special workspaces not receiving focus above fullscreen windows, and cleans up the code
2023-09-21 23:58:58 +01:00
alaricljs
e4ddfcfa0c keybinds: implement pushactivetobottom dispacher (#3217)
Co-authored-by: Leeman <lstrout@enlj.com>
2023-09-21 22:18:26 +01:00
vaxerski
d41a91e050 [gha] Nix: update wlroots 2023-09-21 10:20:18 +00:00
vaxerski
47f38dbc8f deps: update wlroots 2023-09-21 11:19:25 +01:00
Mihai Fufezan
1925e64c21 Vector2D: fix typo in include 2023-09-20 22:26:08 +03:00
vaxerski
62efc045d7 input: lock focus to last surface on buttons held
fixes #3385
2023-09-20 19:50:46 +01:00
Vaxry
ef94375882 doc: Add a CoC (#3366) 2023-09-20 19:38:44 +01:00
Vaxry
0dbd997003 input: Various constraint handling fixes (#3381)
Fixes #3204
2023-09-20 16:47:05 +01:00
memchr
3785defaf1 logging: implement std::formatter for some types (#3380) 2023-09-20 16:25:03 +01:00
memchr
6594b50e57 logging/format: use std::format_string to catch formatting string errors at compile time (#3377)
* fix(log): use constexpr format string

* deprecate getFormat
2023-09-20 08:26:20 +01:00
Dickby
d8d0cd75c2 internal: Make part of CCompositor::focusWindow a bit easier to read. (#3356) 2023-09-19 11:37:30 +01:00
memchr
c50072b108 varlist: cleanup unintuitive string splitting (#3369)
* refactor(varlist): replace unintuitive string splitting

* refactor(varlist): remove test asserts
2023-09-19 09:44:54 +01:00
vaxerski
60f10e6037 hyprctl: print monitor IDs as int64 2023-09-19 00:41:56 +01:00
vaxerski
e4d6695375 keybinds: focus last window on workspace change to another mon 2023-09-18 11:33:19 +01:00
Dickby
b0a82c04df bezier: Remove Todo about N-Point bezier curves. (#3352) 2023-09-17 18:48:11 +01:00
vaxerski
af15b15b4b input: guard constraint in unconstrainMouse 2023-09-17 16:46:04 +01:00
Mihai Fufezan
f72e04d63b misc: add disable_hypr_chan option (#3343) 2023-09-17 15:26:24 +01:00
vaxerski
c8cc811e85 nix: update patches for meson changes 2023-09-17 00:08:19 +01:00
vaxerski
c0082519ae wlroots: disable wlr vulkan support
Hyprland will never use vulkan so this is completely redundant
2023-09-17 00:02:11 +01:00
vaxerski
2f01a18989 window: recalculate layout on swallow in map
fixes #2848
2023-09-16 18:40:57 +01:00
Dickby
a53ec98b82 bezier: Optimize CBezierCurve::getYForPoint (#3321) 2023-09-16 18:32:33 +01:00
fufexan
d126d2c092 [gha] Nix: update inputs 2023-09-16 00:03:39 +00:00
Jeremy Huang
cc630c90b5 master: partially revert 0e64dd2e and fix the animation (#3327) 2023-09-15 22:13:23 +01:00
vaxerski
b9b38424b0 input: fix hints not being used if committed at the beginning 2023-09-15 21:01:54 +01:00
memchr
56adec7c1a socket2: emit lockgroups event (#3317) 2023-09-15 12:06:59 +01:00
MightyPlaza
824290c791 windowrules: fix workspace exec rule with special (#3316)
modified:   src/events/Windows.cpp
2023-09-15 12:05:21 +01:00
Jeremy Huang
d3cbec2d1a master: Add mfact dispatcher (#3298)
* add mfact dispatcher

* limit mfact to between 0.05 and 0.95

* add try catch block for stof

* change log to err
2023-09-15 12:03:05 +01:00
Mihai Fufezan
f8008e4b3b Nix CI: use DetSys' install & cache actions 2023-09-14 17:55:53 +03:00
vaxerski
2536630049 dwindle: fix moving windows on special 2023-09-14 15:37:45 +01:00
memchr
e6651334f2 refactor: flatten nesting ifs in layout window creation method (#3294) 2023-09-14 12:27:16 +01:00
Jeremy Huang
0e64dd2ea5 master: respect the resizing animation option in master layout (#3300) 2023-09-14 12:14:10 +01:00
memchr
db2b72adee config: fix relative path resolution (#3308) 2023-09-14 12:07:31 +01:00
memchr
0dc8289b02 dwindle: fix: don't merge groups when moving window (#3302) 2023-09-14 11:56:29 +01:00
Mihai Fufezan
f6473aa3ad flake.lock: update nixpkgs and xdph
- nix/module: update xdph override
- nix/overlays: remove hyprland-share-picker (now built directly inside xdph)
2023-09-14 12:03:48 +03:00
memchr
84f8f4d77d keybinds: warp cursor to correct window in moveWindowOutOfGroup (#3290) 2023-09-13 15:02:21 +01:00
Jeremy Huang
2ad429dfe0 master: Fix the wrong resize speed in master layout center orientation (#3289)
* rebase

* change isStackVertical variable to make it more readable

* fix some code getting unnecessarily repeating in a loop
2023-09-13 11:48:19 +01:00
memchr
4f88897fc0 keybinds: avoid onWindowRemoved & onWindowCreated when group has one member (#3286)
Make moveWindowOutOfGroup behave like toggleGroup on a group with single
member, this prevents the window from moving around rabidly.
2023-09-13 11:44:02 +01:00
vaxerski
41e5f401c5 keybinds: simulate movement on empty focus after workspace change 2023-09-13 11:36:41 +01:00
vaxerski
b884544ee6 input: don't refocus on switched workspace on the same monitor 2023-09-13 11:33:36 +01:00
memchr
6b1ac659e0 layout: add direction parameter to onWindowCreated and friends (#3269)
* feat(layout): add direction parameter to onWindowCreated and friends

In addition:

- Implement directional moveWindowOutOfGroup for `movewindoworgroup`
  when using dwindle layout. (augmentation of #3006)
- Replace `DWindleLayout::OneTimeFocus` with `IHyprLayout::eDirection`.
- Slight formatting change (clang-format).

* fix: nullptr dereference in dwindle window creation

* refactor: generalized eDirection

* refactor: eliminate DIRECTION_NONE

* Update IHyprLayout.hpp
2023-09-13 11:13:29 +01:00
outfoxxed
b0d5e4008b layout: Allow the layout to control how windows are raised in groups (#3275)
* Allow the layout to control how windows are raised in groups

Previously windows could only be focused if they weren't hidden or
were part of a group. This shifts the logic for picking the window out
of a group to the layout allowing for alternate group implementations
to function normally.

* Fix doc comment consistency

* Fix tabs in comments
2023-09-12 22:37:08 +01:00
vaxerski
be19773aaa windowrules: fix workspace rule separation
fixes #3265
2023-09-12 16:50:10 +01:00
vaxerski
2e34548aea varlist: move to a separate header, add join 2023-09-12 16:50:10 +01:00
memchr
5cc53c14d9 config: add wildcard handling in source= (#3276) 2023-09-12 12:54:05 +01:00
alaricljs
9192b20b96 windowrules: add on-screen constraint to wrv2 'move' (#3247)
* add on-screen constraint to wrv2 'move'

* review changes

* std::clamp

* more parens

---------

Co-authored-by: Leeman <lstrout@enlj.com>
2023-09-12 09:56:20 +01:00
Mihai Fufezan
b6191cbc76 CI: don't run wlroots update in PRs 2023-09-12 11:48:30 +03:00
Mihai Fufezan
ed51fe7bac CI: add reusable actions 2023-09-12 01:40:57 +03:00
memchr
bc41d7ec85 fix: inconsistent behaviour where last workspace was not saved (#3261) 2023-09-11 23:39:24 +01:00
memchr
df51c45d7f keybinds: unify changeworkspace dispatcher (#3250)
* refactor: changeworkspace dispatcher

* refactor: remove redundant focusWindow calls

* refactor(changeworkspace): warp cursor to middle of last focused window

* refactor: use rememberPrevWorkspace

* Fix: `CWorkspace::rememberPreWorkspace` condition is illogical
2023-09-11 15:14:43 +01:00
vaxerski
5a6d0e9963 refactor: fix missed middle() call in CKeybindManager 2023-09-11 12:19:21 +01:00
alaricljs
99fac59938 keybinds: movewindow to screen edge for floating windows (#3245)
* movewindow to screen edge for floating windows

* review changes

* constify vars

---------

Co-authored-by: Leeman <lstrout@enlj.com>
Co-authored-by: vaxerski <vaxry@vaxry.net>
2023-09-11 10:23:57 +01:00
memchr
e96e0dc02d refactor: utilize 'middle()' method for window/montior center (#3253) 2023-09-11 10:09:34 +01:00
vaxerski
3859607b6c input: do not process mouse in unsafe state 2023-09-10 23:44:47 +01:00
memchr
ac2f1a9c30 feat: add a new movewindoworgroup dispatcher (#3006) 2023-09-10 23:29:10 +01:00
alaricljs
81661b49aa windowrules: add % to resizeparams (#3246)
Co-authored-by: Leeman <lstrout@enlj.com>
2023-09-10 23:26:14 +01:00
memchr
79862c957c layout: add missing groupbar decoration to the window (#3235)
* fix: add missing groupbar decoration to the window

Add groupbar decoration to the operand window of `CWindow::insertWindowToGroup` if it does not exist, to prevent segmentation faults when mouse events are triggered after moving the window to a group, where `getDecorationByType(DECORATION_GROUPBAR)` unexpectedly returns nullptr.

Also fixed a bug where the group bar disappeared when the moveIntoGroup dispatcher's operand window was in a group.

* Update Window.cpp
2023-09-10 22:59:10 +01:00
Jeremy Huang
19bbdeed47 master: Add smart resizing option for master layout (#3210)
* add smart resizing for master layout

* fix smart resizing workspace check

* master layout fix smart resize when at max size

* change resizing for center orientation so it doesnt use all nodes

* master layout resizing, simplify code for calculating total height and weight

* remove the redundant smart resizing check
2023-09-10 22:58:06 +01:00
vaxerski
0d53401217 xwayland: adjust coord calculation
coord exactly at the corner would be calc'd wrong
2023-09-10 20:19:09 +01:00
Mihai Fufezan
1e60802968 [gha] Nix: bump wlroots 2023-09-10 20:32:54 +03:00
vaxerski
d28725c678 keybinds: ignore conditions on special release
while the previous commit ignores mods, we also need to ignore other conditions to avoid dangling presses
2023-09-10 16:54:14 +01:00
vaxerski
dcb909df04 keybinds: track pressed special binds
Ignore mods only if we're processing a special bind, and only if it's pressed. Otherwise we might shadow normal key releases via ignoring mods. Fixes #3240
2023-09-10 16:27:14 +01:00
vaxerski
807fc20525 deps: update wlroots 2023-09-10 13:18:22 +01:00
Philip Damianik
6c855dd6e4 internal: Fix wlr output management (#3234) 2023-09-10 13:14:27 +01:00
vaxerski
d490f198a4 keybinds: ignore mods on release of special binds
fixes #3208
2023-09-10 13:13:15 +01:00
memchr
a781c152ff fix(layout): remove focusWindow calls from onWindowCreatedTiling (#3233) 2023-09-10 12:55:18 +01:00
memchr
f7f70c9e72 refactor: replace lambdas with CKeybindManager::switchToWindow (#3229)
moves `switchToWindow` lambdas to a single private method
`CKeybindManager::switchToWindow()`.

fixes #3227, as a by-product of the mouse motion simulation at the end
of `CKeybindManager::switchToWindow()`.
2023-09-10 12:51:27 +01:00
vaxerski
f4e99a36a9 input: don't warp region constraints 2023-09-10 12:49:53 +01:00
Philip Damianik
1a6f961de2 hyprctl: Make device configs queryable (#3226)
* Make device configs queryable

Signed-off-by: pdamianik <39028343+pdamianik@users.noreply.github.com>

* Add set property to getoption output

---------

Signed-off-by: pdamianik <39028343+pdamianik@users.noreply.github.com>
2023-09-09 12:25:17 +01:00
shadowmax31
c061946a94 keybinds: Do not suppress pass and mouse release (#3219) 2023-09-09 10:15:24 +01:00
memchr
6648274735 fix: focusWindow on hidden workspace triggers another focusWindow. (#3216)
This commit address an issue where focusing a window on a hidden
workspace inadvertently triggered a second `focusWindow` call due to
simulated mouse movement. This behaviour led to the incorrect focus on
the window under the cursor instead of target window of method
`focusWindow()`, disrupting `focusurgentorlast` and `focuscurrentorlast`
dispatchers. Introduced a flag to the `CMonitor::changeWorkspace()`
method to prevent simulated mouse movements. This flag is set to false
by default. Changed the `focusWindow()` method accordingly to set this
flag to true when the target window is in a hidden workspace.
2023-09-08 19:17:04 +02:00
vaxerski
398e861b55 internal: fix warnings 2023-09-07 16:43:01 +02:00
Mihai Fufezan
0be6b03ee9 Nix: use gcc13Stdenv 2023-09-07 11:20:08 +03:00
vaxerski
cc5852faa2 config: disable blur special by default
very expensive
2023-09-07 00:35:44 +02:00
vaxerski
b2516010b7 hyprctl: fix missing comma in getopt -j
Fixes #3200
2023-09-06 23:52:25 +02:00
Mihai Fufezan
0d5a6f3168 Nix: fix xdph build 2023-09-07 00:52:19 +03:00
Mihai Fufezan
1581666171 flake.lock: update xdph and nixpkgs 2023-09-07 00:32:38 +03:00
Philip Damianik
8c83852704 internal: Remove all .c_str() calls when using std::vformat (#3198)
Signed-off-by: pdamianik <39028343+pdamianik@users.noreply.github.com>
2023-09-06 21:45:37 +02:00
Philip Damianik
60c01dab01 config: Integrate HASCONFIG into CConfigManager::getConfigValueSafeDevice (#3195) 2023-09-06 19:16:46 +02:00
Philip Damianik
a15e3e1f38 config/input: Improve fallback behavior for unset device config values (#3184)
* Fix fallback behavior for unset device config values

* Replace overload with default argument for fallback config key

* Remove default value for fallback argument in source

* Fix typos
2023-09-06 16:14:18 +02:00
vaxerski
a1cc99a986 pch: add format 2023-09-06 14:59:34 +02:00
unrealhoang
f90a009e93 input/config: add button scroll lock (#3189) 2023-09-06 14:54:48 +02:00
vaxerski
8b9cc9a8db animationmgr: guard monitor ptr in animationSlide 2023-09-06 13:05:37 +02:00
vaxerski
37e2311a3e config: loosen restrictions around animation keywords
Fixes #3185, makes hyprland ignore further args if an animation is disabled
2023-09-06 12:58:01 +02:00
Vaxry
61a71c65ac internal: Formatter rework (#3186) 2023-09-06 12:51:36 +02:00
vaxerski
c3a83daa1e monitor: minor adjustments 2023-09-05 22:16:14 +02:00
Dickby
fa3de9b70e renderer: Fix blur for passes set to 0. (#3181) 2023-09-05 16:33:40 +02:00
vaxerski
2d100bf57e socket2: add renameWorkspace event 2023-09-05 15:55:24 +02:00
Dickby
28f1f035b1 animationmgr: Optimize CAnimationManager::scheduleTick a bit. (#3172)
* Optimize CAnimationManager::scheduleTick a bit.

* Use integer in wl_event_source_timer_update call.
2023-09-05 15:06:39 +02:00
vaxerski
db48f973fd xdgoutput: do not destroy resources on monitorRemoved 2023-09-05 13:33:08 +02:00
Mihai Fufezan
4ddcda93f5 Nix: remove hidpi patches 2023-09-04 21:12:27 +03:00
memchr
8e9f010ee0 build: use PCH to reduce compile time (#3095) 2023-09-04 19:56:02 +02:00
vaxerski
4eecb8bffc config: don't enable vrr 2 for maximized workspaces
fixes #3162
2023-09-04 18:24:18 +02:00
vaxerski
d9937fcdba input: minor constraint fixes
fixes the confined region, warping issues, etc. Closes #3158
2023-09-04 17:34:19 +02:00
vaxerski
e3c83ab2e0 xwaylandmgr: find closest output in xwayland coord translation
partially off-screen windows would be snapped to 0,0 otherwise
2023-09-04 17:30:48 +02:00
shadowmax31
b4c832a1f2 master: Add orientationcycle command on MasterLayout (#3128) 2023-09-04 16:45:58 +02:00
vaxerski
9f3a64481e dwindle: add proper movement for window move binds
ditches the "movewindow = swapwindow" mechanism. Fixes #2804
2023-09-04 15:34:13 +02:00
memchr
69439871e6 refactor: replace manual iteration of CWindow with existing methods (#3147) 2023-09-04 15:13:39 +02:00
MightyPlaza
6a0e2bbff3 socket2: added "activespecial" IPC event (#3163) 2023-09-04 15:11:51 +02:00
vaxerski
32f75ebb70 renderer: separate workspace window render logic
Makes the logic used to render stuff over the windows (special, popups, ime, lockscreen) unified by yeeting the workspace window logic (which is separate cuz fullscreen windows) into their own funcs. Fixes #2053
2023-09-04 15:07:56 +02:00
vaxerski
35df4693ea animatedvariable: don't reset timers on duplicate setters
Fixes the annoying jump when a recalc happens while a window is being animated
2023-09-04 13:11:56 +02:00
MightyPlaza
8fefb180b1 windowrules: Monitor rule fix (#3157)
* fix monitor rules
modified:   src/events/Windows.cpp

* exec on workspace as silent when special is open
modified:   src/events/Windows.cpp
2023-09-03 17:23:13 +02:00
vaxerski
5126bfab72 monitor: ignore no-op workspace changes 2023-09-03 17:21:55 +02:00
vaxerski
96d555e8e7 props: bump ver to 0.29.1 2023-09-03 13:32:57 +02:00
vaxerski
c6c820d16d layout: always center floating xdg windows 2023-09-03 13:07:40 +02:00
vaxerski
e6ca4b6eee window: check for special id matching in close_special_on_empty 2023-09-03 13:02:05 +02:00
vaxerski
5e0cf7d6a5 special: add misc:close_special_on_empty
fixes #3156
2023-09-03 13:00:06 +02:00
staz
01c6c5ae22 internal: Revert rounding of window size (#3153)
* Revert "renderer: round coords and size in renderWindow"

This reverts commit fc0c1896e0.

* Revert "xwaylandmgr: round reported sizes"

This reverts commit 2985e20e6a.
2023-09-03 12:51:48 +02:00
vaxerski
423b129b24 renderer: don't set enabled in applyMonitorRule 2023-09-03 12:43:57 +02:00
MightyPlaza
00bee91bbc internal: workspace rule handling refactor (#3116)
modified:   src/events/Windows.cpp
2023-09-02 20:41:02 +02:00
vaxerski
d4ec54d048 renderer: render IME popups in fullscreen
fixes #1353
2023-09-02 20:32:15 +02:00
memchr
69ce11a063 fix: use-after-free of CWindow* in CHyprGroupBarDecoration::draw (#3146) 2023-09-02 19:58:01 +02:00
vaxerski
204a580544 keybinds: fixup global conditions 2023-09-02 19:36:12 +02:00
vaxerski
1ecfb5e852 globalshortcuts: allow empty appid 2023-09-02 19:32:05 +02:00
vaxerski
f69c5469d7 readme: refactor and update a bit 2023-09-02 00:21:57 +02:00
vaxerski
2985e20e6a xwaylandmgr: round reported sizes
Since we round the sizes in the renderer, it's also a good idea to round the sizes reported to the apps. Fixes #3138
2023-09-02 00:04:55 +02:00
vaxerski
d2a785dfe3 renderer: fixup occlusion conditions
fixes #3123 I fucking hate yall
2023-09-01 23:01:59 +02:00
vaxerski
563fe83db2 keybinds: set special monitor id before recalc
set special workspace's monitor ID before we call recalculateMonitor in toggleSpecialWorkspace. Fixes #1151
2023-09-01 22:57:23 +02:00
vaxerski
f242f9447b keybinds: suppress up event if down was consumed
Fixes #3000
2023-09-01 22:14:10 +02:00
Vaxry
d9292800a2 internal: Unsafe state reworks (#3114) 2023-09-01 22:03:56 +02:00
vaxerski
774a5bedf8 waylandResource: remove user data in markDefunct and not ~dtor 2023-09-01 20:03:58 +02:00
vaxerski
8314341ffe readme: remove wlr_ext workspace proto support mention 2023-09-01 17:22:46 +02:00
vaxerski
b48f810a12 meson/cmake: remove refs to ext-workspace-unstable-v1 2023-09-01 17:14:56 +02:00
vaxerski
bb0933437f wlr-ext-workspace: remove protocol impl
Various reasons: 1st, memory issues. 2nd, MR got closed (see https://gitlab.freedesktop.org/wlroots/wlr-protocols/-/merge_requests/35) 3rd, not needed anymore (waybar has its own hyprland/workspaces module)
2023-09-01 17:10:03 +02:00
q234rty
5035f5fc68 text-input-v1: Fix preedit styling in chromium (#3131) 2023-09-01 16:39:15 +02:00
memchr
1a13d44d5d refactor: raise SIGABRT instead of write to null address (#3124) 2023-08-31 22:52:02 +02:00
vaxerski
fc0c1896e0 renderer: round coords and size in renderWindow 2023-08-31 09:55:38 +02:00
vaxerski
9c4f776757 keybinds: fixup release conditions
honestly I already forgot why the m_vHeldBack vec existed. Seems useless and annoying. Fixes #3113
2023-08-30 23:23:35 +02:00
MightyPlaza
b10cae3010 decos: groupbar mouse interaction (#3102)
* allow groupbar clicking
	modified:   src/Window.cpp
	modified:   src/Window.hpp
	modified:   src/managers/input/InputManager.cpp
	modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
	modified:   src/render/decorations/CHyprGroupBarDecoration.hpp

* remove setting pos inside insertWindowToGroup()

modified:   src/Window.cpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp
modified:   src/managers/KeybindManager.cpp

* add group window by index and group size functions
modified:   src/Window.cpp
modified:   src/Window.hpp
modified:   src/managers/input/InputManager.cpp

* allow dragging into groupbar
modified:   src/Window.cpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp

* allow dragging from groupbar
modified:   src/managers/KeybindManager.cpp

* try groupbar clicking before border resize
modified:   src/managers/input/InputManager.cpp

* block grabbing groupbar on floating (crash)

remove later when crashing is fixed

modified:   src/managers/KeybindManager.cpp

* remove redundant { }
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp

* implement getWindowDecorationBox()
modified:   src/Window.cpp
modified:   src/Window.hpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/input/InputManager.cpp
modified:   src/render/decorations/CHyprDropShadowDecoration.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
modified:   src/render/decorations/IHyprWindowDecoration.cpp
modified:   src/render/decorations/IHyprWindowDecoration.hpp

* fix crash when moveoutofgroup in floating windows

also removes dragging from floating windows limitation

modified:   src/layout/IHyprLayout.cpp
modified:   src/managers/KeybindManager.cpp

* use CRegion in getWindowDecorationBox()
modified:   src/helpers/Region.cpp
modified:   src/helpers/Region.hpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/input/InputManager.cpp
modified:   src/render/decorations/IHyprWindowDecoration.cpp
modified:   src/render/decorations/IHyprWindowDecoration.hpp

* add groupbar scrolling
modified:   src/config/ConfigManager.cpp
modified:   src/managers/input/InputManager.cpp

* change name to getWindowDecorationRegion()
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/input/InputManager.cpp
modified:   src/render/decorations/IHyprWindowDecoration.cpp
modified:   src/render/decorations/IHyprWindowDecoration.hpp

* make dragging from group less hacky for floating
modified:   src/managers/KeybindManager.cpp
2023-08-30 17:39:22 +02:00
vaxerski
c98a00678c input: fix xwayland constraint calcs
some minor adjustments, fixes #3028
2023-08-30 17:23:35 +02:00
vaxerski
b4f123d1f2 compositor: remove wlr_scene refs
super old leftovers
2023-08-30 17:22:55 +02:00
vaxerski
28a90d6055 input: warp in unconstrainMouse
XWayland coord translation would fuck up if we did this in destroyConstraint
2023-08-30 13:42:17 +02:00
vaxerski
32f4059b37 screencopy: fix region sharing
translate before scaling if we are not dividing the coords
2023-08-30 13:17:26 +02:00
vaxerski
84c4a14dad opengl: cleanup framebuffer style 2023-08-29 23:24:35 +02:00
NotAShelf
c5084f36c6 nix: bump nixpkgs
adresses recent mesa version bump in nixpkgs
2023-08-29 17:34:40 +01:00
167 changed files with 9007 additions and 6515 deletions

View File

@@ -39,8 +39,8 @@ jobs:
mkdir hyprland/assets
cp ./LICENSE hyprland/
cp build/Hyprland hyprland/
cp hyprctl/hyprctl hyprland/
cp subprojects/wlroots/build/libwlroots.so.12032 hyprland/
cp build/hyprctl/hyprctl hyprland/
cp subprojects/wlroots/build/libwlroots.so.13032 hyprland/
cp build/Hyprland hyprland/
cp -r example/ hyprland/
cp -r assets/ hyprland/
@@ -105,4 +105,4 @@ jobs:
- 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
run: make release

View File

@@ -15,17 +15,16 @@ jobs:
steps:
- name: Install deps
run: sudo apt install pandoc
- name: Clone repository
uses: actions/checkout@v3
# Not needed
# with:
# submodules: recursive
with:
token: ${{ secrets.PAT }}
- name: Build man pages
run: make man
- uses: stefanzweifel/git-auto-commit-action@v4
name: Commit
with:
commit_message: "[gha] build man pages"
commit_user_name: Mihai Fufezan
commit_user_email: fufexan@protonmail.com
commit_author: Mihai Fufezan <fufexan@protonmail.com>

View File

@@ -1,26 +0,0 @@
name: Build Hyprland (Nix)
on: [push, pull_request, workflow_dispatch]
jobs:
nix:
name: "Build Hyprland (Nix)"
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
with:
submodules: recursive
- name: Install nix
uses: cachix/install-nix-action@v20
with:
install_url: https://nixos.org/nix/install
extra_nix_config: |
auto-optimise-store = true
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
experimental-features = nix-command flakes
- uses: cachix/cachix-action@v12
with:
name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Build packages
run: nix flake check --print-build-logs --accept-flake-config

29
.github/workflows/nix-build.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
on:
workflow_call:
secrets:
CACHIX_AUTH_TOKEN:
required: false
jobs:
build:
strategy:
matrix:
package:
- hyprland
- xdg-desktop-portal-hyprland
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
with:
ref: ${{ github.ref }}
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v12
with:
name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- run: nix build -L ${{ matrix.command }}

15
.github/workflows/nix-ci.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Nix
on: [push, pull_request, workflow_dispatch]
jobs:
wlroots:
if: github.event_name != 'pull_request'
uses: ./.github/workflows/nix-update-wlroots.yml
secrets: inherit
build:
if: always() && !cancelled() && !contains(needs.*.result, 'failure')
needs: wlroots
uses: ./.github/workflows/nix-build.yml
secrets: inherit

View File

@@ -1,40 +0,0 @@
name: "Nix update"
on:
schedule:
- cron: '0 0 * * *'
jobs:
update:
name: "inputs"
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
- name: Install nix
uses: cachix/install-nix-action@v20
with:
install_url: https://nixos.org/nix/install
extra_nix_config: |
auto-optimise-store = true
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
experimental-features = nix-command flakes
- name: Update lockfile
run: nix/update-inputs.sh
- uses: cachix/cachix-action@v12
with:
name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Build packages
run: nix flake check --print-build-logs --accept-flake-config
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "[gha] Nix: bump inputs"
commit_user_name: Mihai Fufezan
commit_user_email: fufexan@protonmail.com
commit_author: Mihai Fufezan <fufexan@protonmail.com>

29
.github/workflows/nix-update-inputs.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: Nix
on:
schedule:
- cron: '0 0 * * *' # check daily
jobs:
update:
name: inputs
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
with:
token: ${{ secrets.PAT }}
- uses: DeterminateSystems/nix-installer-action@main
- name: Update inputs
run: nix/update-inputs.sh
- name: Commit
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "[gha] Nix: update inputs"
update-build:
needs: update
uses: ./.github/workflows/nix-build.yml
secrets: inherit

View File

@@ -1,38 +0,0 @@
name: "Nix update"
on: [push, workflow_dispatch]
jobs:
update:
name: "wlroots"
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
- name: Install nix
uses: cachix/install-nix-action@v20
with:
install_url: https://nixos.org/nix/install
extra_nix_config: |
auto-optimise-store = true
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
experimental-features = nix-command flakes
- name: Update lockfile
run: nix/update-wlroots.sh
- uses: cachix/cachix-action@v12
with:
name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Build packages
run: nix flake check --print-build-logs --accept-flake-config
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "[gha] Nix: bump wlroots"
commit_user_name: Mihai Fufezan
commit_user_email: fufexan@protonmail.com
commit_author: Mihai Fufezan <fufexan@protonmail.com>

View File

@@ -0,0 +1,26 @@
name: Nix
on:
workflow_call:
secrets:
PAT:
required: true
jobs:
update:
name: wlroots
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
with:
token: ${{ secrets.PAT }}
- uses: DeterminateSystems/nix-installer-action@main
- name: Update lockfile
run: nix/update-wlroots.sh
- name: Commit
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "[gha] Nix: update wlroots"

View File

@@ -15,10 +15,15 @@ jobs:
with:
submodules: recursive
- name: Generate version
id: genversion
run: |
bash -c scripts/generateVersion.sh
mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
- name: Create tarball with submodules
id: tar
run: |
sed -i "1s/^/#define GIT_COMMIT_HASH \"$(git rev-parse HEAD)\"\n#define GIT_TAG \"$(git describe --tags)\"\n/" ./src/macros.hpp
mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
- id: whatrelease

2
.gitignore vendored
View File

@@ -29,3 +29,5 @@ gmon.out
*.tar.gz
PKGBUILD
src/version.h

125
CMakeLists.txt Normal file → Executable file
View File

@@ -21,37 +21,51 @@ message(STATUS "Gathering git info")
# Get git info
# hash and branch
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND git rev-parse HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND sh -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g'"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_MESSAGE
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND sh -c "git diff-index --quiet HEAD -- || echo \"dirty\""
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DIRTY
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND sh -c "git describe --tags"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_TAG
OUTPUT_STRIP_TRAILING_WHITESPACE)
COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
#
#
# udis
add_subdirectory("subprojects/udis86")
# wlroots
message(STATUS "Setting up wlroots")
include(ExternalProject)
if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
if(BUILDTYPE_LOWER STREQUAL "release")
# Pass.
elseif(BUILDTYPE_LOWER STREQUAL "debug")
# Pass.
elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
set(BUILDTYPE_LOWER "debugoptimized")
elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
set(BUILDTYPE_LOWER "minsize")
elseif(BUILDTYPE_LOWER STREQUAL "none")
set(BUILDTYPE_LOWER "plain")
else()
set(BUILDTYPE_LOWER "release")
endif()
else()
set(BUILDTYPE_LOWER "release")
endif()
ExternalProject_Add(
wlroots
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
PATCH_COMMAND sed -E -i -e "s/(soversion = 13)([^032]|$$)/soversion = 13032/g" meson.build
CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> --reconfigure
BUILD_COMMAND ninja -C build
BUILD_ALWAYS true
BUILD_IN_SOURCE true
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032
INSTALL_COMMAND echo "wlroots: install not needed"
)
find_program(WaylandScanner NAMES wayland-scanner)
message(STATUS "Found WaylandScanner at ${WaylandScanner}")
execute_process(
@@ -71,6 +85,7 @@ endif()
include_directories(
.
"src/"
"subprojects/wlroots/include/"
"subprojects/wlroots/build/include/"
"subprojects/udis86/"
@@ -84,14 +99,20 @@ set(CMAKE_ENABLE_EXPORTS TRUE)
message(STATUS "Checking deps...")
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1) # we do not check for wlroots, as we provide it ourselves
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
add_executable(Hyprland ${SRCFILES})
set(TRACY_CPP_FILES "")
if(USE_TRACY)
set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
endif()
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
add_dependencies(Hyprland wlroots)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Setting debug flags")
@@ -100,7 +121,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Enabling ASan")
target_link_libraries(Hyprland asan)
add_compile_options(-fsanitize=address)
target_compile_options(Hyprland PUBLIC -fsanitize=address)
endif()
if(USE_TRACY)
@@ -122,6 +143,12 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
add_link_options(-pg -no-pie -fno-builtin)
endif()
check_include_file("execinfo.h" EXECINFOH)
if(EXECINFOH)
message(STATUS "Configuration supports execinfo")
add_compile_definitions(HAS_EXECINFO)
endif()
include(CheckLibraryExists)
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
if(HAVE_LIBEXECINFO)
@@ -146,28 +173,29 @@ if(NO_SYSTEMD)
message(STATUS "SYSTEMD support is disabled...")
else()
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined) checking deps...")
pkg_check_modules(LIBSYSTEMD libsystemd)
check_include_file("systemd/sd-daemon.h" SYSTEMDH)
if(LIBSYSTEMD_FOUND AND SYSTEMDH)
add_compile_definitions(USES_SYSTEMD)
target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}")
if(SYSTEMDH)
pkg_check_modules(LIBSYSTEMD libsystemd)
if (LIBSYSTEMD_FOUND)
add_compile_definitions(USES_SYSTEMD)
target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}")
message(STATUS "Systemd found")
else()
message(WARNING "Systemd support requested but systemd libraries were not found")
endif()
else()
message(WARNING "Systemd support requested but libsystemd or systemd headers were not found")
message(WARNING "Systemd support requested but systemd headers were not found")
endif()
endif()
target_compile_definitions(Hyprland
PRIVATE
"GIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\""
"GIT_BRANCH=\"${GIT_BRANCH}\""
"GIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE}\""
"GIT_DIRTY=\"${GIT_DIRTY}\""
"GIT_TAG=\"${GIT_TAG}\"")
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
message(STATUS "Setting precompiled headers")
target_precompile_headers(Hyprland PRIVATE $<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::deps)
@@ -193,14 +221,13 @@ function(protocol protoPath protoName external)
endfunction()
target_link_libraries(Hyprland
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.12032 # wlroots is provided by us
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032 # wlroots is provided by us
OpenGL::EGL
OpenGL::GL
Threads::Threads
${CMAKE_SOURCE_DIR}/subprojects/udis86/build/libudis86/liblibudis86.a
libudis86
)
protocol("protocols/ext-workspace-unstable-v1.xml" "ext-workspace-unstable-v1" true)
protocol("protocols/idle.xml" "idle" true)
protocol("protocols/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" true)
protocol("protocols/tablet-unstable-v2.xml" "tablet-unstable-v2" true)
@@ -214,5 +241,9 @@ protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false)
protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false)
protocol("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false)
protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
protocol("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false)
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
# hyprctl
add_subdirectory(hyprctl)

96
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,96 @@
## Goal
Our goal is to provide a space where it is safe for everyone to contribute to,
and get support for, open-source software in a respectful and cooperative
manner.
We value all contributions and want to make this organization and its
surrounding community a place for everyone.
As members, contributors, and everyone else who may participate in the
development, we strive to keep the entire experience civil.
## Standards
Our community standards exist in order to make sure everyone feels comfortable
contributing to the project(s) together.
Our standards are:
- Do not harass, attack, or in any other way discriminate against anyone, including
for their protected traits, including, but not limited to, sex, religion, race,
appearance, gender, identity, nationality, sexuality, etc.
- Do not go off-topic, do not post spam.
- Treat everyone with respect.
Examples of breaking each rule respectively include:
- Harassment, bullying or inappropriate jokes about another person.
- Posting distasteful imagery, trolling, or posting things unrelated to the topic at hand.
- Treating someone as worse because of their lack of understanding of an issue.
## Enforcement
Enforcement of this CoC is done by the members of the hyprwm organization.
We, as the organization, will strive our best to keep this community civil and
following the standards outlined above.
### Reporting incidents
If you believe an incident of breaking our standards has occurred, but nobody has
taken appropriate action, you can privately contact the people responsible for dealing
with such incidents in multiple ways:
***E-Mail***
- `vaxry[at]vaxry.net`
- `mihai[at]fufexan.net`
***Discord***
- `@vaxry`
- `@fufexan`
***Matrix***
- `@vaxry:matrix.vaxry.net`
- `@fufexan:matrix.org`
We, as members, guarantee your privacy and will not share those reports with anyone.
## Enforcement Strategy
Depending on the severity of the infraction, any action from the list below may be applied.
Please keep in mind cases are reviewed on a per-case basis and members are the ultimate
deciding factor in the type of punishment.
If the matter would benefit from an outside opinion, a member might reach for more opinions
from people unrelated to the organization, however, the final decision regarding the action
to be taken is still up to the member.
For example, if the matter at hand regards a representative of a marginalized group or minority,
the member might ask for a first-hand opinion from another representative of such group.
### Correction/Edit
If your message is found to be misleading or poorly worded, a member might
edit your message.
### Warning/Deletion
If your message is found inappropriate, a member might give you a public or private warning,
and/or delete your message.
### Mute
If your message is disruptive, or you have been repeatedly violating the standards,
a member might mute (or temporarily ban) you.
### Ban
If your message is hateful, very disruptive, or other, less serious infractions are repeated
ignoring previous punishments, a member might ban you permanently.
## Scope
This CoC shall apply to all projects ran under the `hyprwm` organization and all _official_ communities
outside of GitHub.
However, it is worth noting that official communities outside of GitHub might have their own,
additional sets of rules.

View File

@@ -3,103 +3,72 @@ PREFIX = /usr/local
legacyrenderer:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
legacyrendererdebug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
release:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
debug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
chmod -R 777 ./build
clear:
rm -rf build
rm -f ./protocols/*-protocol.h ./protocols/*-protocol.c
rm -f ./hyprctl/hyprctl
rm -rf ./subprojects/wlroots/build
all:
@if [[ "$EUID" = 0 ]]; then echo -en "Avoid running $(MAKE) all as sudo.\n"; fi
$(MAKE) clear
$(MAKE) fixwlr
cd ./subprojects/wlroots && meson setup build/ --buildtype=release && ninja -C build/ && mkdir -p ${PREFIX}/lib/ && cp ./build/libwlroots.so.12032 ${PREFIX}/lib/ || echo "Could not install libwlroots to ${PREFIX}/lib/libwlroots.so.12032"
cd subprojects/udis86 && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B./build -G Ninja && cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
$(MAKE) release
$(MAKE) -C hyprctl all
install:
$(MAKE) clear
$(MAKE) fixwlr
cd ./subprojects/wlroots && meson setup build/ --buildtype=release && ninja -C build/ && mkdir -p ${PREFIX}/lib/ && cp ./build/libwlroots.so.12032 ${PREFIX}/lib/ || echo "Could not install libwlroots to ${PREFIX}/lib/libwlroots.so.12032"
cd subprojects/udis86 && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B./build -G Ninja && cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` && cd ../..
$(MAKE) release
$(MAKE) -C hyprctl all
@if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
@echo -en "!NOTE: Please note make install does not compile Hyprland and only installs the already built files."
mkdir -p ${PREFIX}/share/wayland-sessions
mkdir -p ${PREFIX}/bin
cp -f ./build/Hyprland ${PREFIX}/bin
cp -f ./hyprctl/hyprctl ${PREFIX}/bin
cp -f ./build/hyprctl/hyprctl ${PREFIX}/bin
chmod 755 ${PREFIX}/bin/Hyprland
chmod 755 ${PREFIX}/bin/hyprctl
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
mkdir -p ${PREFIX}/share/hyprland
cp ./assets/wall_* ${PREFIX}/share/hyprland
mkdir -p ${PREFIX}/share/xdg-desktop-portal
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
mkdir -p ${PREFIX}/share/man/man1
install -m644 ./docs/*.1 ${PREFIX}/share/man/man1
mkdir -p ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland/protocols
mkdir -p ${PREFIX}/include/hyprland/wlroots
mkdir -p ${PREFIX}/share/pkgconfig
mkdir -p ${PREFIX}/share/xdg-desktop-portal
find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
cd subprojects/wlroots/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots && cd ../../..
cd subprojects/wlroots/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots && cd ../../../..
cp ./protocols/*-protocol.h ${PREFIX}/include/hyprland/protocols
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal/
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
mkdir -p ${PREFIX}/lib/
cp ./subprojects/wlroots/build/libwlroots.so.13032 ${PREFIX}/lib/
cleaninstall:
echo -en "$(MAKE) cleaninstall has been DEPRECATED, you should avoid using it in the future.\nRunning $(MAKE) install instead...\n"
$(MAKE) install
$(MAKE) installheaders
uninstall:
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
rm -f ${PREFIX}/bin/Hyprland
rm -f ${PREFIX}/bin/hyprctl
rm -f ${PREFIX}/lib/libwlroots.so.12032
rm -f ${PREFIX}/lib/libwlroots.so.13032
rm -rf ${PREFIX}/share/hyprland
rm -f ${PREFIX}/share/man/man1/Hyprland.1
rm -f ${PREFIX}/share/man/man1/hyprctl.1
fixwlr:
sed -E -i -e 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
rm -rf ./subprojects/wlroots/build
config:
$(MAKE) fixwlr
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=release -Dwerror=false -Dexamples=false
ninja -C subprojects/wlroots/build/
ninja -C subprojects/wlroots/build/ install
cd subprojects/udis86 && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja && cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
pluginenv:
cd subprojects/udis86 && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja && cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
$(MAKE) fixwlr
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=release -Dwerror=false -Dexamples=false
ninja -C subprojects/wlroots/build/
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
@exit 1
installheaders:
@if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
mkdir -p ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland/protocols
@@ -113,13 +82,8 @@ pluginenv:
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
configdebug:
$(MAKE) fixwlr
meson setup subprojects/wlroots/build subprojects/wlroots --prefix=${PREFIX} --buildtype=debug -Dwerror=false -Dexamples=false -Db_sanitize=address
ninja -C subprojects/wlroots/build/
ninja -C subprojects/wlroots/build/ install
chmod -R 755 ${PREFIX}/include/hyprland
chmod 755 ${PREFIX}/share/pkgconfig
man:
pandoc ./docs/Hyprland.1.rst \

View File

@@ -16,7 +16,8 @@
Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks.
It supports multiple layouts, fancy effects, has a very flexible IPC model allowing for a lot of customization, a powerful plugin system and more.
It provides the latest Wayland features, is highly customizable, has all the eyecandy, the most powerful plugins,
easy IPC, much more QoL stuff than other wlr-based compositors and more...
<br>
<br>
@@ -32,40 +33,29 @@ It supports multiple layouts, fancy effects, has a very flexible IPC model allow
<br>
</div>
# Notice
Hyprland is still in pretty early development compared to some other Wayland compositors.
Although Hyprland is pretty stable, it may have some bugs.
# Features
- All of the eyecandy: gradient borders, blur, animations, shadows and much more
- A lot of customization
- Much more QoL stuff than other wlr-based compositors
- Custom bezier curves for the best animations
- Powerful plugin support
- Tearing support for better gaming performance
- Easily expandable and readable codebase
- Plugin support
- Fast and active development
- Not scared to provide bleeding-edge features
- Config reloaded instantly upon saving
- Custom bezier curve based animations
- Dual Kawase blur
- Drop shadows
- Rounded corners
- Gradient borders
- Fully dynamic workspaces
- Two built-in layouts and more available as plugins
- Closely follows `wlroots-git`
- Global keybinds passed to your apps of choice
- A lot of customization
- Bundled wlroots
- Window/layer fade in/out
- Tiling/pseudotiling/floating/fullscreen windows
- Switching workspaces between window modes on the fly
- Special workspaces (scratchpads)
- Window/monitor rules
- Window groups (tabbed mode)
- Powerful window/monitor/layer rules
- Socket-based IPC
- `wlr_ext` workspaces protocol support
- Event system for bash scripts
- Full damage tracking
- Docks support
- Drawing tablet support
- Native IME + Input panels support
- Native IME and Input Panels Support
- and much more...
<br>
@@ -90,15 +80,6 @@ Although Hyprland is pretty stable, it may have some bugs.
<br>
<br>
# Stars Over Time
<br>
[![Stars Preview]][Stars]
<br>
<br>
</div>
# Special Thanks
@@ -147,8 +128,8 @@ Although Hyprland is pretty stable, it may have some bugs.
<!----------------------------------{ Images }--------------------------------->
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
[Preview A]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png
[Preview B]: https://i.ibb.co/SX7GbYR/winter-rice.png
[Preview A]: https://i.ibb.co/C1yTb0r/falf.png
[Preview B]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png

View File

@@ -1,2 +1,2 @@
[preferred]
default=hyprland
default=hyprland;gtk

View File

@@ -33,8 +33,8 @@ void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset
(m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
// draw the border
wlr_box fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE),
(int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
CBox fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE),
(int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
fullBox.x -= pMonitor->vecPosition.x;
fullBox.y -= pMonitor->vecPosition.y;
@@ -49,9 +49,9 @@ void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset
if (fullBox.width < 1 || fullBox.height < 1)
return; // don't draw invisible shadows
g_pHyprOpenGL->scissor((wlr_box*)nullptr);
g_pHyprOpenGL->scissor((CBox*)nullptr);
scaleBox(&fullBox, pMonitor->scale);
fullBox.scale(pMonitor->scale);
g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
}
@@ -68,7 +68,7 @@ void CCustomDecoration::updateWindow(CWindow* pWindow) {
}
void CCustomDecoration::damageEntire() {
wlr_box dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y),
(int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
CBox dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y),
(int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
g_pHyprRenderer->damageBox(&dm);
}

View File

@@ -58,8 +58,8 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
HyprlandAPI::addNotification(PHANDLE, "Hello World from an example plugin!", CColor{0.f, 1.f, 1.f, 1.f}, 5000);
HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, std::any data) { onActiveWindowChange(self, data); });
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, std::any data) { onNewWindow(self, data); });
HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, SCallbackInfo& info, std::any data) { onActiveWindowChange(self, data); });
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, SCallbackInfo& info, std::any data) { onNewWindow(self, data); });
g_pCustomLayout = std::make_unique<CHyprCustomLayout>();

View File

@@ -19,6 +19,10 @@ monitor=,preferred,auto,auto
# Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf
# Set programs that you use
$terminal = kitty
$fileManager = dolphin
$menu = wofi --show drun
# Some default env vars.
env = XCURSOR_SIZE,24
@@ -49,6 +53,9 @@ general {
col.inactive_border = rgba(595959aa)
layout = dwindle
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = false
}
decoration {
@@ -60,6 +67,8 @@ decoration {
enabled = true
size = 3
passes = 1
vibrancy = 0.1696
}
drop_shadow = true
@@ -99,6 +108,11 @@ gestures {
workspace_swipe = false
}
misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
}
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
device:epic-mouse-v1 {
@@ -110,18 +124,19 @@ device:epic-mouse-v1 {
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
$mainMod = SUPER
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind = $mainMod, Q, exec, kitty
bind = $mainMod, Q, exec, $terminal
bind = $mainMod, C, killactive,
bind = $mainMod, M, exit,
bind = $mainMod, E, exec, dolphin
bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating,
bind = $mainMod, R, exec, wofi --show drun
bind = $mainMod, R, exec, $menu
bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, togglesplit, # dwindle
@@ -155,6 +170,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
# Example special workspace (scratchpad)
bind = $mainMod, S, togglespecialworkspace, magic
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
# Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1

20
flake.lock generated
View File

@@ -25,11 +25,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1692638711,
"narHash": "sha256-J0LgSFgJVGCC1+j5R2QndadWI1oumusg6hCtYAzLID4=",
"lastModified": 1700612854,
"narHash": "sha256-yrQ8osMD+vDLGFX7pcwsY/Qr5PUd6OmDMYJZzZi0+zc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "91a22f76cd1716f9d0149e8a5c68424bb691de15",
"rev": "19cbff58383a4ae384dea4d1d0c823d72b49d614",
"type": "github"
},
"original": {
@@ -67,18 +67,18 @@
"flake": false,
"locked": {
"host": "gitlab.freedesktop.org",
"lastModified": 1692976565,
"narHash": "sha256-eBKkG7tMxg92NskEn8dHRFY245JwjirWRoOZzW6DnUw=",
"lastModified": 1701368958,
"narHash": "sha256-7kvyoA91etzVEl9mkA/EJfB6z/PltxX7Xc4gcr7/xlo=",
"owner": "wlroots",
"repo": "wlroots",
"rev": "717ded9bb0191ea31bf4368be32e7a15fe1b8294",
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
"type": "gitlab"
},
"original": {
"host": "gitlab.freedesktop.org",
"owner": "wlroots",
"repo": "wlroots",
"rev": "717ded9bb0191ea31bf4368be32e7a15fe1b8294",
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
"type": "gitlab"
}
},
@@ -95,11 +95,11 @@
]
},
"locked": {
"lastModified": 1691841170,
"narHash": "sha256-RCTm1/MVWYPnReMgyp7tr2ogGYo/pvw38jZaFwemgPU=",
"lastModified": 1700508250,
"narHash": "sha256-X4o/mifI7Nhu0UKYlxx53wIC+gYDo3pVM9L2u3PE2bE=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "57a3a41ba6b358109e4fc25c6a4706b5f7d93c6b",
"rev": "eb120ff25265ecacd0fc13d7dab12131b60d0f47",
"type": "github"
},
"original": {

View File

@@ -12,7 +12,7 @@
host = "gitlab.freedesktop.org";
owner = "wlroots";
repo = "wlroots";
rev = "717ded9bb0191ea31bf4368be32e7a15fe1b8294";
rev = "5d639394f3e83b01596dcd166a44a9a1a2583350";
flake = false;
};
@@ -65,10 +65,8 @@
hyprland
hyprland-unwrapped
hyprland-debug
hyprland-nvidia
# hyprland-extras
xdg-desktop-portal-hyprland
hyprland-share-picker
# dependencies
hyprland-protocols
wlroots-hyprland
@@ -77,7 +75,9 @@
});
devShells = eachSystem (system: {
default = pkgsFor.${system}.mkShell {
default = pkgsFor.${system}.mkShell.override {
stdenv = pkgsFor.${system}.gcc13Stdenv;
} {
name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
buildInputs = [self.packages.${system}.wlroots-hyprland];

8
hyprctl/CMakeLists.txt Normal file
View File

@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.19)
project(
hyprctl
DESCRIPTION "Control utility for Hyprland"
)
add_executable(hyprctl "main.cpp")

View File

@@ -1,4 +1,4 @@
all:
$(CXX) -std=c++2b ./main.cpp -o ./hyprctl
$(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl
clean:
rm ./hyprctl

View File

@@ -12,6 +12,7 @@
#include <ranges>
#include <algorithm>
#include <signal.h>
#include <format>
#include <iostream>
#include <string>
@@ -28,6 +29,7 @@ commands:
monitors
workspaces
activeworkspace
workspacerules
clients
activewindow
layers
@@ -50,6 +52,7 @@ commands:
notify
globalshortcuts
instances
layouts
flags:
-j -> output in JSON
@@ -106,20 +109,6 @@ std::vector<SInstanceData> instances() {
return result;
}
std::string getFormat(const char* fmt, ...) {
char* outputStr = nullptr;
va_list args;
va_start(args, fmt);
vasprintf(&outputStr, fmt, args);
va_end(args);
std::string output = std::string(outputStr);
free(outputStr);
return output;
}
void request(std::string arg, int minArgs = 0) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -248,19 +237,19 @@ void instancesRequest(bool json) {
if (!json) {
for (auto& el : inst) {
result += getFormat("instance %s:\n\ttime: %llu\n\tpid: %llu\n\twl socket: %s\n\n", el.id.c_str(), el.time, el.pid, el.wlSocket.c_str());
result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket);
}
} else {
result += '[';
for (auto& el : inst) {
result += getFormat(R"#(
{
"instance": "%s",
"time": %llu,
"pid": %llu,
"wl_socket": "%s"
},)#",
el.id.c_str(), el.time, el.pid, el.wlSocket.c_str());
result += std::format(R"#(
{{
"instance": "{}",
"time": {},
"pid": {},
"wl_socket": "{}"
}},)#",
el.id, el.time, el.pid, el.wlSocket);
}
result.pop_back();
@@ -286,7 +275,6 @@ bool isNumber(const std::string& str, bool allowfloat) {
}
int main(int argc, char** argv) {
int bflag = 0, sflag = 0, index, c;
bool parseArgs = true;
if (argc < 2) {
@@ -300,7 +288,7 @@ int main(int argc, char** argv) {
bool json = false;
std::string overrideInstance = "";
for (auto i = 0; i < ARGS.size(); ++i) {
for (std::size_t i = 0; i < ARGS.size(); ++i) {
if (ARGS[i] == "--") {
// Stop parsing arguments after --
parseArgs = false;
@@ -354,7 +342,7 @@ int main(int argc, char** argv) {
const auto INSTANCES = instances();
if (INSTANCENO < 0 || INSTANCENO >= INSTANCES.size()) {
if (INSTANCENO < 0 || static_cast<std::size_t>(INSTANCENO) >= INSTANCES.size()) {
std::cout << "no such instance\n";
return 1;
}
@@ -383,6 +371,8 @@ int main(int argc, char** argv) {
request(fullRequest);
else if (fullRequest.contains("/activeworkspace"))
request(fullRequest);
else if (fullRequest.contains("/workspacerules"))
request(fullRequest);
else if (fullRequest.contains("/activewindow"))
request(fullRequest);
else if (fullRequest.contains("/layers"))
@@ -407,6 +397,8 @@ int main(int argc, char** argv) {
request(fullRequest);
else if (fullRequest.contains("/globalshortcuts"))
request(fullRequest);
else if (fullRequest.contains("/rollinglog"))
request(fullRequest);
else if (fullRequest.contains("/instances"))
instancesRequest(json);
else if (fullRequest.contains("/switchxkblayout"))
@@ -429,6 +421,8 @@ int main(int argc, char** argv) {
request(fullRequest, 2);
else if (fullRequest.contains("/hyprpaper"))
requestHyprpaper(fullRequest);
else if (fullRequest.contains("/layouts"))
request(fullRequest);
else if (fullRequest.contains("/--help"))
printf("%s", USAGE.c_str());
else {

View File

@@ -20,26 +20,20 @@ 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_COMMIT_HASH = run_command('git', 'rev-parse', 'HEAD', 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('sh', '-c', 'git diff-index --quiet HEAD -- || echo "dirty"', check: false).stdout().strip()
add_project_arguments(
[
'-Wno-unused-parameter',
'-Wno-unused-value',
'-Wno-missing-field-initializers',
'-Wno-narrowing',
f'-DGIT_BRANCH="@GIT_BRANCH@"',
f'-DGIT_COMMIT_HASH="@GIT_COMMIT_HASH@"',
f'-DGIT_COMMIT_MESSAGE="@GIT_COMMIT_MESSAGE@"',
f'-DGIT_DIRTY="@GIT_DIRTY@"',
],
language: 'cpp')
wlroots = subproject('wlroots', default_options: ['examples=false'])
if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif
wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
have_xwlr = wlroots.get_variable('features').get('xwayland')
xcb_dep = dependency('xcb', required: get_option('xwayland'))
@@ -75,6 +69,8 @@ if get_option('buildtype') == 'debug'
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
endif
version_h = run_command('sh', '-c', 'scripts/generateVersion.sh')
globber = run_command('find', 'src', '-name', '*.h*', check: true)
headers = globber.stdout().strip().split('\n')
foreach file : headers

View File

@@ -1,5 +1,6 @@
{
lib,
fetchurl,
stdenv,
pkg-config,
makeWrapper,
@@ -10,6 +11,7 @@
git,
hyprland-protocols,
jq,
libGL,
libdrm,
libinput,
libxcb,
@@ -26,7 +28,6 @@
xcbutilwm,
xwayland,
debug ? false,
enableNvidiaPatches ? false,
enableXWayland ? true,
legacyRenderer ? false,
withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
@@ -34,13 +35,25 @@
version ? "git",
commit,
# deprecated flags
enableNvidiaPatches ? false,
nvidiaPatches ? false,
hidpiXWayland ? false,
}:
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been renamed `enableNvidiaPatches`";
let
# NOTE: remove after https://github.com/NixOS/nixpkgs/pull/271096 reaches nixos-unstable
libdrm_2_4_118 = libdrm.overrideAttrs(attrs: rec {
version = "2.4.118";
src = fetchurl {
url = "https://dri.freedesktop.org/${attrs.pname}/${attrs.pname}-${version}.tar.xz";
hash = "sha256-p3e9hfK1/JxX+IbIIFgwBXgxfK/bx30Kdp1+mpVnq4g=";
};
});
in
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
stdenv.mkDerivation {
pname = "hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}${lib.optionalString debug "-debug"}";
pname = "hyprland${lib.optionalString debug "-debug"}";
inherit version;
src = lib.cleanSourceWith {
@@ -71,7 +84,8 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
git
cairo
hyprland-protocols
libdrm
libGL
libdrm_2_4_118
libinput
libxkbcommon
mesa
@@ -80,7 +94,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
wayland
wayland-protocols
pciutils
(wlroots.override {inherit enableNvidiaPatches;})
wlroots
]
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
++ lib.optionals withSystemd [systemd];
@@ -90,8 +104,9 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
then "debug"
else "release";
mesonAutoFeatures = "disabled";
mesonFlags = builtins.concatLists [
["-Dauto_features=disabled"]
(lib.optional enableXWayland "-Dxwayland=enabled")
(lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
(lib.optional withSystemd "-Dsystemd=enabled")
@@ -105,9 +120,15 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
postPatch = ''
# Fix hardcoded paths to /usr installation
sed -i "s#/usr#$out#" src/render/OpenGL.cpp
substituteInPlace meson.build \
--replace "@GIT_COMMIT_HASH@" '${commit}' \
--replace "@GIT_DIRTY@" '${
# Generate version.h
cp src/version.h.in src/version.h
substituteInPlace src/version.h \
--replace "@HASH@" '${commit}' \
--replace "@BRANCH@" "" \
--replace "@MESSAGE@" "" \
--replace "@TAG@" "" \
--replace "@DIRTY@" '${
if commit == ""
then "dirty"
else ""

View File

@@ -7,7 +7,6 @@ self: {
cfg = config.wayland.windowManager.hyprland;
defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
enableXWayland = cfg.xwayland.enable;
inherit (cfg) enableNvidiaPatches;
};
in {
disabledModules = ["services/window-managers/hyprland.nix"];
@@ -35,12 +34,10 @@ in {
defaultText = lib.literalExpression ''
hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override {
enableXWayland = config.wayland.windowManager.hyprland.xwayland.enable;
inherit (config.wayland.windowManager.hyprland) enableNvidiaPatches;
}
'';
description = lib.mdDoc ''
Hyprland package to use. Will override the 'xwayland' and
'enableNvidiaPatches' options.
Hyprland package to use. Will override the 'xwayland' option.
Defaults to the one provided by the flake. Set it to
{package}`pkgs.hyprland` to use the one provided by nixpkgs or
@@ -86,8 +83,6 @@ in {
xwayland.enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;};
enableNvidiaPatches = lib.mkEnableOption (lib.mdDoc "patching wlroots for better Nvidia support.");
extraConfig = lib.mkOption {
type = lib.types.nullOr lib.types.lines;
default = "";
@@ -173,5 +168,7 @@ in {
imports = [
(lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "hidpi"]
"Support for this option has been removed. Refer to https://wiki.hyprland.org/Configuring/XWayland for more info")
(lib.mkRemovedOptionModule ["wayland" "windowManager" "hyprland" "xwayland" "enableNvidiaPatches"]
"Nvidia patches are no longer needed for Hyprland")
];
}

View File

@@ -10,9 +10,7 @@ with lib; let
inherit (pkgs.stdenv.hostPlatform) system;
finalPortalPackage = cfg.portalPackage.override {
hyprland-share-picker = inputs.xdph.packages.${system}.hyprland-share-picker.override {
hyprland = cfg.finalPackage;
};
hyprland = cfg.finalPackage;
};
in {
# disables Nixpkgs Hyprland module to avoid conflicts
@@ -39,7 +37,6 @@ in {
readOnly = true;
default = cfg.package.override {
enableXWayland = cfg.xwayland.enable;
enableNvidiaPatches = cfg.enableNvidiaPatches;
};
defaultText =
literalExpression
@@ -52,12 +49,6 @@ in {
portalPackage = mkPackageOptionMD inputs.xdph.packages.${system} "xdg-desktop-portal-hyprland" {};
xwayland.enable = mkEnableOption (mdDoc "support for XWayland") // {default = true;};
enableNvidiaPatches =
mkEnableOption null
// {
description = mdDoc "Whether to apply patches to wlroots for better Nvidia support.";
};
};
config = mkIf cfg.enable {
@@ -93,9 +84,14 @@ in {
"XWayland patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland"
)
(
mkRenamedOptionModule
["programs" "hyprland" "nvidiaPatches"]
mkRemovedOptionModule
["programs" "hyprland" "enableNvidiaPatches"]
"Nvidia patches are no longer needed"
)
(
mkRemovedOptionModule
["programs" "hyprland" "nvidiaPatches"]
"Nvidia patches are no longer needed"
)
];
}

View File

@@ -30,6 +30,7 @@ in {
# Hyprland packages themselves
(final: prev: {
hyprland = final.callPackage ./default.nix {
stdenv = final.gcc13Stdenv;
version = "${props.version}+date=${mkDate (self.lastModifiedDate or "19700101")}_${self.shortRev or "dirty"}";
wlroots = final.wlroots-hyprland;
commit = self.rev or "";
@@ -37,7 +38,12 @@ in {
};
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
hyprland-debug = final.hyprland.override {debug = true;};
hyprland-nvidia = final.hyprland.override {enableNvidiaPatches = true;};
hyprland-nvidia =
builtins.trace ''
hyprland-nvidia was removed. Please use the hyprland package.
Nvidia patches are no longer needed.
''
final.hyprland;
hyprland-hidpi =
builtins.trace ''
hyprland-hidpi was removed. Please use the hyprland package.
@@ -51,7 +57,6 @@ in {
# including forked or patched packages for compatibility.
hyprland-extras = mkJoinedOverlays [
inputs.xdph.overlays.xdg-desktop-portal-hyprland
inputs.xdph.overlays.hyprland-share-picker
];
udis86 = final: prev: {

View File

@@ -1,24 +1,12 @@
diff --git a/meson.build b/meson.build
index f3802553..6a924a79 100644
index 1d2c7f9f..c5ef4e67 100644
--- a/meson.build
+++ b/meson.build
@@ -21,9 +21,9 @@ else
@@ -33,20 +33,7 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif
GIT_BRANCH = run_command('git', 'rev-parse', '--abbrev-ref', 'HEAD', check: false).stdout().strip()
-GIT_COMMIT_HASH = run_command('git', 'rev-parse', 'HEAD', check: false).stdout().strip()
+GIT_COMMIT_HASH = '@GIT_COMMIT_HASH@'
GIT_COMMIT_MESSAGE = run_command('sh', '-c', 'git show | head -n 5 | tail -n 1', check: false).stdout().strip()
-GIT_DIRTY = run_command('sh', '-c', 'git diff-index --quiet HEAD -- || echo "dirty"', check: false).stdout().strip()
+GIT_DIRTY = '@GIT_DIRTY@'
add_project_arguments(
[
@@ -39,21 +39,8 @@ add_project_arguments(
],
language: 'cpp')
-wlroots = subproject('wlroots', default_options: ['examples=false'])
-wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
-have_xwlr = wlroots.get_variable('features').get('xwayland')
-xcb_dep = dependency('xcb', required: get_option('xwayland'))
-
@@ -32,17 +20,24 @@ index f3802553..6a924a79 100644
-have_xwayland = xcb_dep.found() and have_xwlr
-
-if not have_xwayland
- add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
+if get_option('xwayland').disabled()
+ add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
@@ -69,8 +56,6 @@ if get_option('buildtype') == 'debug'
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
endif
-version_h = run_command('sh', '-c', 'scripts/generateVersion.sh')
-
globber = run_command('find', 'src', '-name', '*.h*', check: true)
headers = globber.stdout().strip().split('\n')
foreach file : headers
diff --git a/src/meson.build b/src/meson.build
index 7b658d31..60aa4057 100644
index 0af864b9..38723b8c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -7,16 +7,16 @@ executable('Hyprland', src,
@@ -9,16 +9,16 @@ executable('Hyprland', src,
server_protos,
dependency('wayland-server'),
dependency('wayland-client'),

View File

@@ -1,164 +0,0 @@
diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h
index 3d540522..1c5a2e37 100644
--- a/include/xwayland/xwm.h
+++ b/include/xwayland/xwm.h
@@ -88,6 +88,7 @@ enum atom_name {
DND_ACTION_PRIVATE,
NET_CLIENT_LIST,
NET_CLIENT_LIST_STACKING,
+ XWAYLAND_GLOBAL_OUTPUT_SCALE,
ATOM_LAST // keep last
};
@@ -96,6 +97,7 @@ struct wlr_xwm {
struct wl_event_source *event_source;
struct wlr_seat *seat;
uint32_t ping_timeout;
+ uint32_t scale;
xcb_atom_t atoms[ATOM_LAST];
xcb_connection_t *xcb_conn;
diff --git a/xwayland/xwm.c b/xwayland/xwm.c
index 5f857f24..21584ebd 100644
--- a/xwayland/xwm.c
+++ b/xwayland/xwm.c
@@ -19,6 +19,14 @@
#include <xcb/xfixes.h>
#include "xwayland/xwm.h"
+static int32_t scale(struct wlr_xwm *xwm, uint32_t val) {
+ return val * xwm->scale;
+}
+
+static int32_t unscale(struct wlr_xwm *xwm, uint32_t val) {
+ return (val + xwm->scale/2) / xwm->scale;
+}
+
static const char *const atom_map[ATOM_LAST] = {
[WL_SURFACE_ID] = "WL_SURFACE_ID",
[WL_SURFACE_SERIAL] = "WL_SURFACE_SERIAL",
@@ -90,6 +98,7 @@ static const char *const atom_map[ATOM_LAST] = {
[DND_ACTION_PRIVATE] = "XdndActionPrivate",
[NET_CLIENT_LIST] = "_NET_CLIENT_LIST",
[NET_CLIENT_LIST_STACKING] = "_NET_CLIENT_LIST_STACKING",
+ [XWAYLAND_GLOBAL_OUTPUT_SCALE] = "_XWAYLAND_GLOBAL_OUTPUT_SCALE",
};
#define STARTUP_INFO_REMOVE_PREFIX "remove: ID="
@@ -965,8 +974,8 @@ static void xwm_handle_create_notify(struct wlr_xwm *xwm,
return;
}
- xwayland_surface_create(xwm, ev->window, ev->x, ev->y,
- ev->width, ev->height, ev->override_redirect);
+ xwayland_surface_create(xwm, ev->window, unscale(xwm, ev->x), unscale(xwm, ev->y),
+ unscale(xwm, ev->width), unscale(xwm, ev->height), ev->override_redirect);
}
static void xwm_handle_destroy_notify(struct wlr_xwm *xwm,
@@ -997,10 +1006,10 @@ static void xwm_handle_configure_request(struct wlr_xwm *xwm,
struct wlr_xwayland_surface_configure_event wlr_event = {
.surface = surface,
- .x = mask & XCB_CONFIG_WINDOW_X ? ev->x : surface->x,
- .y = mask & XCB_CONFIG_WINDOW_Y ? ev->y : surface->y,
- .width = mask & XCB_CONFIG_WINDOW_WIDTH ? ev->width : surface->width,
- .height = mask & XCB_CONFIG_WINDOW_HEIGHT ? ev->height : surface->height,
+ .x = mask & XCB_CONFIG_WINDOW_X ? unscale(xwm, ev->x) : surface->x,
+ .y = mask & XCB_CONFIG_WINDOW_Y ? unscale(xwm, ev->y) : surface->y,
+ .width = mask & XCB_CONFIG_WINDOW_WIDTH ? unscale(xwm, ev->width) : surface->width,
+ .height = mask & XCB_CONFIG_WINDOW_HEIGHT ? unscale(xwm, ev->height) : surface->height,
.mask = mask,
};
@@ -1015,14 +1024,14 @@ static void xwm_handle_configure_notify(struct wlr_xwm *xwm,
}
bool geometry_changed =
- (xsurface->x != ev->x || xsurface->y != ev->y ||
- xsurface->width != ev->width || xsurface->height != ev->height);
+ (xsurface->x != unscale(xwm, ev->x) || xsurface->y != unscale(xwm, ev->y) ||
+ xsurface->width != unscale(xwm, ev->width) || xsurface->height != unscale(xwm, ev->height));
if (geometry_changed) {
- xsurface->x = ev->x;
- xsurface->y = ev->y;
- xsurface->width = ev->width;
- xsurface->height = ev->height;
+ xsurface->x = unscale(xwm, ev->x);
+ xsurface->y = unscale(xwm, ev->y);
+ xsurface->width = unscale(xwm, ev->width);
+ xsurface->height = unscale(xwm, ev->height);
}
if (xsurface->override_redirect != ev->override_redirect) {
@@ -1133,6 +1142,20 @@ static void xwm_handle_property_notify(struct wlr_xwm *xwm,
xcb_property_notify_event_t *ev) {
struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->window);
if (xsurface == NULL) {
+ if (ev->atom == xwm->atoms[XWAYLAND_GLOBAL_OUTPUT_SCALE]) {
+ xcb_get_property_cookie_t cookie = xcb_get_property(xwm->xcb_conn, 0,
+ ev->window, ev->atom, XCB_ATOM_ANY, 0, 2048);
+ xcb_get_property_reply_t *reply = xcb_get_property_reply(xwm->xcb_conn,
+ cookie, NULL);
+ if (reply == NULL) {
+ return;
+ }
+ if (reply->type == XCB_ATOM_CARDINAL) {
+ xwm->scale = *(uint32_t*)xcb_get_property_value(reply);
+ }
+ free(reply);
+ }
+
return;
}
@@ -1760,16 +1783,17 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,
int old_w = xsurface->width;
int old_h = xsurface->height;
+ struct wlr_xwm *xwm = xsurface->xwm;
+
xsurface->x = x;
xsurface->y = y;
xsurface->width = width;
xsurface->height = height;
- struct wlr_xwm *xwm = xsurface->xwm;
uint32_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT |
XCB_CONFIG_WINDOW_BORDER_WIDTH;
- uint32_t values[] = {x, y, width, height, 0};
+ uint32_t values[] = {scale(xwm, x), scale(xwm, y), scale(xwm, width), scale(xwm, height), 0};
xcb_configure_window(xwm->xcb_conn, xsurface->window_id, mask, values);
// If the window size did not change, then we cannot rely on
@@ -1777,15 +1801,15 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *xsurface,
// we are supposed to send a synthetic event. See ICCCM part
// 4.1.5. But we ignore override-redirect windows as ICCCM does
// not apply to them.
- if (width == old_w && height == old_h && !xsurface->override_redirect) {
+ if (scale(xwm, width) == scale(xwm, old_w) && scale(xwm, height) == scale(xwm, old_h) && !xsurface->override_redirect) {
xcb_configure_notify_event_t configure_notify = {
.response_type = XCB_CONFIGURE_NOTIFY,
.event = xsurface->window_id,
.window = xsurface->window_id,
- .x = x,
- .y = y,
- .width = width,
- .height = height,
+ .x = scale(xwm, x),
+ .y = scale(xwm, y),
+ .width = scale(xwm, width),
+ .height = scale(xwm, height),
};
xcb_send_event(xwm->xcb_conn, 0, xsurface->window_id,
@@ -2122,6 +2146,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
wl_list_init(&xwm->pending_startup_ids);
xwm->ping_timeout = 10000;
+ xwm->scale = 1;
xwm->xcb_conn = xcb_connect_to_fd(wm_fd, NULL);
int rc = xcb_connection_has_error(xwm->xcb_conn);

View File

@@ -1,41 +0,0 @@
diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c
index 9fe934f7..9662d4ee 100644
--- a/render/gles2/renderer.c
+++ b/render/gles2/renderer.c
@@ -176,7 +176,7 @@ static bool gles2_bind_buffer(struct wlr_renderer *wlr_renderer,
assert(wlr_egl_is_current(renderer->egl));
push_gles2_debug(renderer);
- glFlush();
+ glFinish();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
pop_gles2_debug(renderer);
diff --git a/types/output/render.c b/types/output/render.c
index 2e38919a..97f78608 100644
--- a/types/output/render.c
+++ b/types/output/render.c
@@ -240,22 +240,7 @@ bool output_pick_format(struct wlr_output *output,
}
uint32_t wlr_output_preferred_read_format(struct wlr_output *output) {
- struct wlr_renderer *renderer = output->renderer;
- assert(renderer != NULL);
-
- if (!renderer->impl->preferred_read_format || !renderer->impl->read_pixels) {
- return DRM_FORMAT_INVALID;
- }
-
- if (!wlr_output_attach_render(output, NULL)) {
- return false;
- }
-
- uint32_t fmt = renderer->impl->preferred_read_format(renderer);
-
- output_clear_back_buffer(output);
-
- return fmt;
+ return DRM_FORMAT_XRGB8888;
}
struct wlr_render_pass *wlr_output_begin_render_pass(struct wlr_output *output,

View File

@@ -1,493 +0,0 @@
diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
index e3c1aaa50..eba29b5ba 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
@@ -164,6 +164,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);
@@ -195,6 +197,7 @@ xwl_cursor_clear_frame_cb(struct xwl_cursor *xwl_cursor)
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;
@@ -225,8 +228,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);
}
@@ -235,6 +238,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;
@@ -263,8 +267,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 6e0600e4e..4a22ebff0 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
@@ -507,8 +507,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;
@@ -731,13 +731,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);
@@ -887,12 +888,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;
@@ -1382,8 +1384,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);
@@ -1419,8 +1421,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);
}
@@ -2110,8 +2112,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;
@@ -3152,6 +3154,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;
@@ -3163,6 +3166,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 ||
@@ -3171,8 +3175,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 661e1828d..6c60aba34 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
@@ -186,6 +186,9 @@ update_backing_pixmaps(struct xwl_screen *xwl_screen, int width, int height)
static void
update_screen_size(struct xwl_screen *xwl_screen, int width, int height)
{
+ width *= xwl_screen->global_output_scale;
+ height *= xwl_screen->global_output_scale;
+
xwl_screen->width = width;
xwl_screen->height = height;
@@ -597,14 +600,15 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
new_emulated_height);
}
-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;
@@ -623,10 +627,10 @@ apply_output_change(struct xwl_output *xwl_output)
}
if (xwl_output->randr_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.
@@ -686,7 +690,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
@@ -746,7 +750,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
@@ -857,6 +861,8 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id,
RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
RROutputSetConnection(xwl_output->randr_output, RR_Connected);
+
+ 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 a95288e4f..46d1ead2a 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;
@@ -102,6 +102,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 189e7cfd6..555434031 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -764,6 +764,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 (xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
xorg_list_add(&xwl_present_window->frame_callback_list,
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
index 46ab4fed7..b2d7022e6 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"
@@ -111,6 +112,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)
@@ -128,6 +135,38 @@ 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;
+ }
+}
+
+
struct xwl_output *
xwl_screen_get_fixed_or_first_output(struct xwl_screen *xwl_screen)
{
@@ -144,19 +183,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)
- xwl_window_update_property(xwl_window, rec);
+ 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);
+ }
}
static void
@@ -638,8 +682,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
@@ -655,6 +705,30 @@ 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);
+ }
+ }
+}
+
+
static int
xwl_server_grab(ClientPtr client)
{
@@ -712,6 +786,7 @@ 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;
@@ -746,6 +821,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) {
@@ -988,6 +1064,13 @@ 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);
AddCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, pScreen);
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
index fadd0526e..2ce6ce5ab 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
@@ -87,6 +87,7 @@ 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;
@@ -134,6 +135,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;
@@ -166,6 +168,8 @@ 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);
int xwl_screen_get_next_output_serial(struct xwl_screen * xwl_screen);
#endif /* XWAYLAND_SCREEN_H */
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
index 6b7f38605..2f1e0dee1 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
@@ -788,7 +788,8 @@ xwl_create_root_surface(struct xwl_window *xwl_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);
@@ -1322,6 +1323,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

View File

@@ -1,12 +0,0 @@
--- 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;

View File

@@ -1,26 +1,31 @@
{
lib,
fetchurl,
version,
src,
wlroots,
hwdata,
libdisplay-info,
libliftoff,
libdrm,
enableXWayland ? true,
enableNvidiaPatches ? false,
}:
let
# NOTE: remove after https://github.com/NixOS/nixpkgs/pull/271096 reaches nixos-unstable
libdrm_2_4_118 = libdrm.overrideAttrs(old: rec {
version = "2.4.118";
src = fetchurl {
url = "https://dri.freedesktop.org/${old.pname}/${old.pname}-${version}.tar.xz";
hash = "sha256-p3e9hfK1/JxX+IbIIFgwBXgxfK/bx30Kdp1+mpVnq4g=";
};
});
in
wlroots.overrideAttrs (old: {
inherit version src enableXWayland;
pname = "${old.pname}-hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}";
pname = "${old.pname}-hyprland";
patches =
(old.patches or [])
++ (lib.optionals enableNvidiaPatches [
./patches/wlroots-nvidia.patch
]);
buildInputs = old.buildInputs ++ [hwdata libliftoff libdisplay-info];
# HACK: libdrm_2_4_118 is placed at the head of list to take precedence over libdrm in `old.buildInputs`
buildInputs = [libdrm_2_4_118] ++ old.buildInputs ++ [hwdata libliftoff libdisplay-info];
NIX_CFLAGS_COMPILE = toString [
"-Wno-error=maybe-uninitialized"

View File

@@ -1,3 +1,3 @@
{
"version": "0.29.0"
"version": "0.33.0"
}

View File

@@ -1,306 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="ext_workspace_unstable_v1">
<copyright>
Copyright © 2019 Christopher Billington
Copyright © 2020 Ilia Bozhinov
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="zext_workspace_manager_v1" version="1">
<description summary="list and control workspaces">
Workspaces, also called virtual desktops, are groups of surfaces. A
compositor with a concept of workspaces may only show some such groups of
surfaces (those of 'active' workspaces) at a time. 'Activating' a
workspace is a request for the compositor to display that workspace's
surfaces as normal, whereas the compositor may hide or otherwise
de-emphasise surfaces that are associated only with 'inactive' workspaces.
Workspaces are grouped by which sets of outputs they correspond to, and
may contain surfaces only from those outputs. In this way, it is possible
for each output to have its own set of workspaces, or for all outputs (or
any other arbitrary grouping) to share workspaces. Compositors may
optionally conceptually arrange each group of workspaces in an
N-dimensional grid.
The purpose of this protocol is to enable the creation of taskbars and
docks by providing them with a list of workspaces and their properties,
and allowing them to activate and deactivate workspaces.
After a client binds the zext_workspace_manager_v1, each workspace will be
sent via the workspace event.
</description>
<event name="workspace_group">
<description summary="a workspace group has been created">
This event is emitted whenever a new workspace group has been created.
All initial details of the workspace group (workspaces, outputs) will be
sent immediately after this event via the corresponding events in
zext_workspace_group_handle_v1.
</description>
<arg name="workspace_group" type="new_id" interface="zext_workspace_group_handle_v1"/>
</event>
<request name="commit">
<description summary="all requests about the workspaces have been sent">
The client must send this request after it has finished sending other
requests. The compositor must process a series of requests preceding a
commit request atomically.
This allows changes to the workspace properties to be seen as atomic,
even if they happen via multiple events, and even if they involve
multiple zext_workspace_handle_v1 objects, for example, deactivating one
workspace and activating another.
</description>
</request>
<event name="done">
<description summary="all information about the workspace groups has been sent">
This event is sent after all changes in all workspace groups have been
sent.
This allows changes to one or more zext_workspace_group_handle_v1
properties to be seen as atomic, even if they happen via multiple
events. In particular, an output moving from one workspace group to
another sends an output_enter event and an output_leave event to the two
zext_workspace_group_handle_v1 objects in question. The compositor sends
the done event only after updating the output information in both
workspace groups.
</description>
</event>
<event name="finished">
<description summary="the compositor has finished with the workspace_manager">
This event indicates that the compositor is done sending events to the
zext_workspace_manager_v1. The server will destroy the object
immediately after sending this request, so it will become invalid and
the client should free any resources associated with it.
</description>
</event>
<request name="stop">
<description summary="stop sending events">
Indicates the client no longer wishes to receive events for new
workspace groups. However the compositor may emit further workspace
events, until the finished event is emitted.
The client must not send any more requests after this one.
</description>
</request>
</interface>
<interface name="zext_workspace_group_handle_v1" version="1">
<description summary="a workspace group assigned to a set of outputs">
A zext_workspace_group_handle_v1 object represents a a workspace group
that is assigned a set of outputs and contains a number of workspaces.
The set of outputs assigned to the workspace group is conveyed to the client via
output_enter and output_leave events, and its workspaces are conveyed with
workspace events.
For example, a compositor which has a set of workspaces for each output may
advertise a workspace group (and its workspaces) per output, whereas a compositor
where a workspace spans all outputs may advertise a single workspace group for all
outputs.
</description>
<event name="output_enter">
<description summary="output assigned to workspace group">
This event is emitted whenever an output is assigned to the workspace
group.
</description>
<arg name="output" type="object" interface="wl_output"/>
</event>
<event name="output_leave">
<description summary="output removed from workspace group">
This event is emitted whenever an output is removed from the workspace
group.
</description>
<arg name="output" type="object" interface="wl_output"/>
</event>
<event name="workspace">
<description summary="workspace added to workspace group">
This event is emitted whenever a new workspace has been created.
All initial details of the workspace (name, coordinates, state) will
be sent immediately after this event via the corresponding events in
zext_workspace_handle_v1.
</description>
<arg name="workspace" type="new_id" interface="zext_workspace_handle_v1"/>
</event>
<event name="remove">
<description summary="this workspace group has been destroyed">
This event means the zext_workspace_group_handle_v1 has been destroyed.
It is guaranteed there won't be any more events for this
zext_workspace_group_handle_v1. The zext_workspace_group_handle_v1 becomes
inert so any requests will be ignored except the destroy request.
The compositor must remove all workspaces belonging to a workspace group
before removing the workspace group.
</description>
</event>
<request name="create_workspace">
<description summary="create a new workspace">
Request that the compositor create a new workspace with the given name.
There is no guarantee that the compositor will create a new workspace,
or that the created workspace will have the provided name.
</description>
<arg name="workspace" type="string"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the zext_workspace_handle_v1 object">
Destroys the zext_workspace_handle_v1 object.
This request should be called either when the client does not want to
use the workspace object any more or after the remove event to finalize
the destruction of the object.
</description>
</request>
</interface>
<interface name="zext_workspace_handle_v1" version="1">
<description summary="a workspace handing a group of surfaces">
A zext_workspace_handle_v1 object represents a a workspace that handles a
group of surfaces.
Each workspace has a name, conveyed to the client with the name event; a
list of states, conveyed to the client with the state event; and
optionally a set of coordinates, conveyed to the client with the
coordinates event. The client may request that the compositor activate or
deactivate the workspace.
Each workspace can belong to only a single workspace group.
Depepending on the compositor policy, there might be workspaces with
the same name in different workspace groups, but these workspaces are still
separate (e.g. one of them might be active while the other is not).
</description>
<event name="name">
<description summary="workspace name changed">
This event is emitted immediately after the zext_workspace_handle_v1 is
created and whenever the name of the workspace changes.
</description>
<arg name="name" type="string"/>
</event>
<event name="coordinates">
<description summary="workspace coordinates changed">
This event is used to organize workspaces into an N-dimensional grid
within a workspace group, and if supported, is emitted immediately after
the zext_workspace_handle_v1 is created and whenever the coordinates of
the workspace change. Compositors may not send this event if they do not
conceptually arrange workspaces in this way. If compositors simply
number workspaces, without any geometric interpretation, they may send
1D coordinates, which clients should not interpret as implying any
geometry. Sending an empty array means that the compositor no longer
orders the workspace geometrically.
Coordinates have an arbitrary number of dimensions N with an uint32
position along each dimension. By convention if N > 1, the first
dimension is X, the second Y, the third Z, and so on. The compositor may
chose to utilize these events for a more novel workspace layout
convention, however. No guarantee is made about the grid being filled or
bounded; there may be a workspace at coordinate 1 and another at
coordinate 1000 and none in between. Within a workspace group, however,
workspaces must have unique coordinates of equal dimensionality.
</description>
<arg name="coordinates" type="array"/>
</event>
<event name="state">
<description summary="the state of the workspace changed">
This event is emitted immediately after the zext_workspace_handle_v1 is
created and each time the workspace state changes, either because of a
compositor action or because of a request in this protocol.
</description>
<arg name="state" type="array"/>
</event>
<enum name="state">
<description summary="types of states on the workspace">
The different states that a workspace can have.
</description>
<entry name="active" value="0" summary="the workspace is active"/>
<entry name="urgent" value="1" summary="the workspace requests attention"/>
<entry name="hidden" value="2">
<description summary="the workspace is not visible">
The workspace is not visible in its workspace group, and clients
attempting to visualize the compositor workspace state should not
display such workspaces.
</description>
</entry>
</enum>
<event name="remove">
<description summary="this workspace has been destroyed">
This event means the zext_workspace_handle_v1 has been destroyed. It is
guaranteed there won't be any more events for this
zext_workspace_handle_v1. The zext_workspace_handle_v1 becomes inert so
any requests will be ignored except the destroy request.
</description>
</event>
<request name="destroy" type="destructor">
<description summary="destroy the zext_workspace_handle_v1 object">
Destroys the zext_workspace_handle_v1 object.
This request should be called either when the client does not want to
use the workspace object any more or after the remove event to finalize
the destruction of the object.
</description>
</request>
<request name="activate">
<description summary="activate the workspace">
Request that this workspace be activated.
There is no guarantee the workspace will be actually activated, and
behaviour may be compositor-dependent. For example, activating a
workspace may or may not deactivate all other workspaces in the same
group.
</description>
</request>
<request name="deactivate">
<description summary="activate the workspace">
Request that this workspace be deactivated.
There is no guarantee the workspace will be actually deactivated.
</description>
</request>
<request name="remove">
<description summary="remove the workspace">
Request that this workspace be removed.
There is no guarantee the workspace will be actually removed.
</description>
</request>
</interface>
</protocol>

View File

@@ -25,11 +25,11 @@ protocols = [
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
['wlr-foreign-toplevel-management-unstable-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['wlr-output-power-management-unstable-v1.xml'],
['wlr-screencopy-unstable-v1.xml'],
['ext-workspace-unstable-v1.xml'],
['pointer-constraints-unstable-v1.xml'],
['tablet-unstable-v2.xml'],
['idle.xml'],

14
scripts/generateVersion.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
cp -fr ./src/version.h.in ./src/version.h
HASH=$(git rev-parse HEAD)
BRANCH=$(git rev-parse --abbrev-ref HEAD)
MESSAGE=$(git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g')
DIRTY=$(git diff-index --quiet HEAD -- || echo dirty)
TAG=$(git describe --tags)
sed -i -e "s#@HASH@#${HASH}#" ./src/version.h
sed -i -e "s#@BRANCH@#${BRANCH}#" ./src/version.h
sed -i -e "s#@MESSAGE@#${MESSAGE}#" ./src/version.h
sed -i -e "s#@DIRTY@#${DIRTY}#" ./src/version.h
sed -i -e "s#@TAG@#${TAG}#" ./src/version.h

File diff suppressed because it is too large Load Diff

View File

@@ -27,8 +27,10 @@
#include "render/OpenGL.hpp"
#include "hyprerror/HyprError.hpp"
#include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp"
enum eManagersInitStage {
enum eManagersInitStage
{
STAGE_PRIORITY = 0,
STAGE_LATE
};
@@ -52,7 +54,6 @@ class CCompositor {
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_xdg_activation_v1* m_sWLRXDGActivation;
wlr_output_layout* m_sWLROutputLayout;
wlr_idle* m_sWLRIdle;
wlr_idle_notifier_v1* m_sWLRIdleNotifier;
wlr_layer_shell_v1* m_sWLRLayerShell;
wlr_xdg_shell* m_sWLRXDGShell;
@@ -61,12 +62,9 @@ class CCompositor {
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
wlr_output_manager_v1* m_sWLROutputMgr;
wlr_presentation* m_sWLRPresentation;
wlr_scene* m_sWLRScene;
wlr_input_inhibit_manager* m_sWLRInhibitMgr;
wlr_keyboard_shortcuts_inhibit_manager_v1* m_sWLRKbShInhibitMgr;
wlr_egl* m_sWLREGL;
int m_iDRMFD;
wlr_ext_workspace_manager_v1* m_sWLREXTWorkspaceMgr;
wlr_pointer_constraints_v1* m_sWLRPointerConstraints;
wlr_relative_pointer_manager_v1* m_sWLRRelPointerMgr;
wlr_server_decoration_manager* m_sWLRServerDecoMgr;
@@ -86,6 +84,7 @@ class CCompositor {
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr;
wlr_tearing_control_manager_v1* m_sWLRTearingControlMgr;
// ------------------------------------------------- //
std::string m_szWLDisplaySocket = "";
@@ -120,7 +119,9 @@ class CCompositor {
bool m_bReadyToProcess = false;
bool m_bSessionActive = true;
bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; // because wlroots
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bIsShuttingDown = false;
// ------------------------------------------------- //
@@ -135,11 +136,12 @@ class CCompositor {
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
bool windowExists(CWindow*);
bool windowValidMapped(CWindow*);
CWindow* vectorToWindow(const Vector2D&);
CWindow* vectorToWindowIdeal(const Vector2D&); // used only for finding a window to focus on, basically a "findFocusableWindow"
CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow"
CWindow* vectorToWindowTiled(const Vector2D&);
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
SIMEPopup* vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopup>& popups);
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
CWindow* windowFromCursor();
CWindow* windowFloatingFromCursor();
CMonitor* getMonitorFromOutput(wlr_output*);
@@ -151,7 +153,6 @@ class CCompositor {
CWorkspace* getWorkspaceByID(const int&);
CWorkspace* getWorkspaceByName(const std::string&);
CWorkspace* getWorkspaceByString(const std::string&);
CWorkspace* getWorkspaceByWorkspaceHandle(const wlr_ext_workspace_handle_v1*);
void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&);
int getWindowsOnWorkspace(const int&);
@@ -162,10 +163,9 @@ class CCompositor {
CWindow* getFullscreenWindowOnWorkspace(const int&);
bool doesSeatAcceptInput(wlr_surface*);
bool isWindowActive(CWindow*);
void moveWindowToTop(CWindow*);
void changeWindowZOrder(CWindow*, bool);
void cleanupFadingOut(const int& monid);
CWindow* getWindowInDirection(CWindow*, char);
void deactivateAllWLRWorkspaces(wlr_ext_workspace_handle_v1* exclude = nullptr);
CWindow* getNextWindowOnWorkspace(CWindow*, bool focusableOnly = false);
CWindow* getPrevWindowOnWorkspace(CWindow*, bool focusableOnly = false);
int getNextAvailableNamedWorkspace();
@@ -204,6 +204,10 @@ class CCompositor {
void notifyIdleActivity();
void setIdleActivityInhibit(bool inhibit);
void arrangeMonitors();
void enterUnsafeState();
void leaveUnsafeState();
void setPreferredScaleForSurface(wlr_surface* pSurface, double scale);
void setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform);
std::string explicitConfigPath;
@@ -211,6 +215,7 @@ class CCompositor {
void initAllSignals();
void setRandomSplash();
void initManagers(eManagersInitStage stage);
void prepareFallbackOutput();
uint64_t m_iHyprlandPID = 0;
};

View File

@@ -1,5 +1,7 @@
#pragma once
#include "helpers/Vector2D.hpp"
enum eIcons
{
ICON_WARNING = 0,
@@ -22,4 +24,26 @@ enum eRenderStage
RENDER_POST_MIRROR, /* After rendering a mirror */
RENDER_PRE_WINDOW, /* Before rendering a window (any pass) Note some windows (e.g. tiled) may have 2 passes (main & popup) */
RENDER_POST_WINDOW, /* After rendering a window (any pass) */
};
struct SCallbackInfo {
bool cancelled = false; /* on cancellable events, will cancel the event. */
};
struct SWindowDecorationExtents {
Vector2D topLeft;
Vector2D bottomRight;
//
SWindowDecorationExtents operator*(const double& scale) const {
return SWindowDecorationExtents{topLeft * scale, bottomRight * scale};
}
SWindowDecorationExtents round() {
return {topLeft.round(), bottomRight.round()};
}
bool operator==(const SWindowDecorationExtents& other) const {
return topLeft == other.topLeft && bottomRight == other.bottomRight;
}
};

View File

@@ -1,6 +1,7 @@
#include "Window.hpp"
#include "Compositor.hpp"
#include "render/decorations/CHyprDropShadowDecoration.hpp"
#include "render/decorations/CHyprGroupBarDecoration.hpp"
CWindow::CWindow() {
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
@@ -12,7 +13,7 @@ CWindow::CWindow() {
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)
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
}
CWindow::~CWindow() {
@@ -20,6 +21,9 @@ CWindow::~CWindow() {
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastWindow = nullptr;
}
g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return other.first == this; });
}
SWindowDecorationExtents CWindow::getFullWindowExtents() {
@@ -36,30 +40,27 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
for (auto& wd : m_dWindowDecorations) {
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this);
const auto EXTENTS = wd->getWindowDecorationExtents();
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
}
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
if (m_pWLSurface.exists() && !m_bIsX11) {
wlr_box surfaceExtents = {0, 0, 0, 0};
CBox surfaceExtents = {0, 0, 0, 0};
// TODO: this could be better, perhaps make a getFullWindowRegion?
wlr_xdg_surface_for_each_popup_surface(
m_uSurface.xdg,
[](wlr_surface* surf, int sx, int sy, void* data) {
wlr_box* pSurfaceExtents = (wlr_box*)data;
CBox* pSurfaceExtents = (CBox*)data;
if (sx < pSurfaceExtents->x)
pSurfaceExtents->x = sx;
if (sy < pSurfaceExtents->y)
@@ -87,21 +88,21 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
return maxExtents;
}
wlr_box CWindow::getFullWindowBoundingBox() {
CBox CWindow::getFullWindowBoundingBox() {
if (m_sAdditionalConfigData.dimAround) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
}
auto maxExtents = getFullWindowExtents();
auto maxExtents = getFullWindowExtents();
wlr_box finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox;
}
wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
@@ -112,7 +113,7 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
POS = PMONITOR->vecPosition;
SIZE = PMONITOR->vecSize;
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
}
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
@@ -130,10 +131,10 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
SIZE.y += PMONITOR->vecReservedBottomRight.y;
}
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
}
wlr_box CWindow::getWindowInputBox() {
CBox CWindow::getWindowInputBox() {
const int BORDERSIZE = getRealBorderSize();
if (m_sAdditionalConfigData.dimAround) {
@@ -143,58 +144,45 @@ wlr_box CWindow::getWindowInputBox() {
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
for (auto& wd : m_dWindowDecorations) {
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
if (!wd->allowsInput())
continue;
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
const auto EXTENTS = wd->getWindowDecorationExtents();
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
}
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
// Add extents to the real base BB and return
wlr_box finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox;
}
CBox CWindow::getWindowMainSurfaceBox() {
return {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
}
SWindowDecorationExtents CWindow::getFullWindowReservedArea() {
SWindowDecorationExtents extents;
for (auto& wd : m_dWindowDecorations) {
const auto RESERVED = wd->getWindowDecorationReservedArea();
if (RESERVED.bottomRight == Vector2D{} && RESERVED.topLeft == Vector2D{})
continue;
extents.topLeft = extents.topLeft + RESERVED.topLeft;
extents.bottomRight = extents.bottomRight + RESERVED.bottomRight;
}
return extents;
return g_pDecorationPositioner->getWindowDecorationReserved(this);
}
void CWindow::updateWindowDecos() {
for (auto& wd : m_dWindowDecorations)
wd->updateWindow(this);
bool recalc = false;
if (!m_bIsMapped || isHidden())
return;
for (auto& wd : m_vDecosToRemove) {
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
if (it->get() == wd) {
g_pDecorationPositioner->uncacheDecoration(it->get());
it = m_dWindowDecorations.erase(it);
recalc = true;
if (it == m_dWindowDecorations.end())
@@ -203,10 +191,30 @@ void CWindow::updateWindowDecos() {
}
}
g_pDecorationPositioner->onWindowUpdate(this);
if (recalc)
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
m_vDecosToRemove.clear();
for (auto& wd : m_dWindowDecorations) {
wd->updateWindow(this);
}
}
void CWindow::addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco) {
m_dWindowDecorations.emplace_back(std::move(deco));
g_pDecorationPositioner->forceRecalcFor(this);
updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
}
void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
m_vDecosToRemove.push_back(deco);
g_pDecorationPositioner->forceRecalcFor(this);
updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
}
pid_t CWindow::getPID() {
@@ -218,6 +226,9 @@ pid_t CWindow::getPID() {
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
} else {
if (!m_bIsMapped || !m_bMappedX11)
return -1;
PID = m_uSurface.xwayland->pid;
}
@@ -324,7 +335,8 @@ void CWindow::updateSurfaceOutputs() {
m_pWLSurface.wlr(),
[](wlr_surface* surf, int x, int y, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
},
this);
}
@@ -333,6 +345,10 @@ void CWindow::moveToWorkspace(int workspaceID) {
if (m_iWorkspaceID == workspaceID)
return;
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
const int OLDWORKSPACE = m_iWorkspaceID;
m_iWorkspaceID = workspaceID;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
@@ -340,7 +356,7 @@ void CWindow::moveToWorkspace(int workspaceID) {
updateSpecialRenderData();
if (PWORKSPACE) {
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", getFormat("%lx,%s", this, PWORKSPACE->m_szName.c_str())});
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", std::format("{:x},{}", (uintptr_t)this, PWORKSPACE->m_szName)});
EMIT_HOOK_EVENT("moveWindow", (std::vector<void*>{this, PWORKSPACE}));
}
@@ -351,6 +367,15 @@ void CWindow::moveToWorkspace(int workspaceID) {
// update xwayland coords
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec());
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) {
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE);
if (PWS) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWS->m_iMonitorID); PMONITOR)
PMONITOR->setSpecialWorkspace(nullptr);
}
}
}
CWindow* CWindow::X11TransientFor() {
@@ -386,6 +411,8 @@ void unregisterVar(void* ptr) {
}
void CWindow::onUnmap() {
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
if (g_pCompositor->m_pLastWindow == this)
g_pCompositor->m_pLastWindow = nullptr;
@@ -405,11 +432,23 @@ void CWindow::onUnmap() {
m_pWLSurface.unassign();
hyprListener_unmapWindow.removeCallback();
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(m_iWorkspaceID) == 0 && g_pCompositor->isWorkspaceSpecial(m_iWorkspaceID)) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
PMONITOR->setSpecialWorkspace(nullptr);
}
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient == this)
PMONITOR->solitaryClient = nullptr;
}
void CWindow::onMap() {
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this));
m_pWLSurface.m_pOwner = this;
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
m_vRealPosition.resetAllCallbacks();
@@ -439,6 +478,8 @@ void CWindow::onMap() {
hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->surface->events.unmap : &m_uSurface.xdg->surface->events.unmap, &Events::listener_unmapWindow, this,
"CWindow");
m_vReportedSize = m_vPendingReportedSize;
}
void CWindow::onBorderAngleAnimEnd(void* ptr) {
@@ -483,15 +524,19 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} else if (r.szRule == "opaque") {
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule.find("rounding") == 0) {
} else if (r.szRule == "immediate") {
m_sAdditionalConfigData.forceTearing = true;
} else if (r.szRule == "nearestneighbor") {
m_sAdditionalConfigData.nearestNeighbor = true;
} else if (r.szRule.starts_with("rounding")) {
try {
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"%s\" failed with: %s", r.szRule.c_str(), e.what()); }
} else if (r.szRule.find("bordersize") == 0) {
} catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("bordersize")) {
try {
m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"%s\" failed with: %s", r.szRule.c_str(), e.what()); }
} else if (r.szRule.find("opacity") == 0) {
} catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("opacity")) {
try {
CVarList vars(r.szRule, 0, ' ');
@@ -521,13 +566,13 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
opacityIDX++;
}
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what()); }
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "noanim") {
m_sAdditionalConfigData.forceNoAnims = true;
} else if (r.szRule.find("animation") == 0) {
} else if (r.szRule.starts_with("animation")) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sAdditionalConfigData.animationStyle = STYLE;
} else if (r.szRule.find("bordercolor") == 0) {
} else if (r.szRule.starts_with("bordercolor")) {
try {
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
@@ -538,17 +583,30 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} else {
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"%s\" failed with: %s", r.szRule.c_str(), e.what()); }
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "dimaround") {
m_sAdditionalConfigData.dimAround = true;
} else if (r.szRule == "keepaspectratio") {
m_sAdditionalConfigData.keepAspectRatio = true;
} else if (r.szRule.find("xray") == 0) {
} else if (r.szRule.starts_with("xray")) {
CVarList vars(r.szRule, 0, ' ');
try {
m_sAdditionalConfigData.xray = configStringToInt(vars[1]);
} catch (...) {}
} else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (IDLERULE == "none")
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
else if (IDLERULE == "always")
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
else if (IDLERULE == "focus")
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
else if (IDLERULE == "fullscreen")
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
}
}
@@ -571,6 +629,9 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.borderSize = -1;
m_sAdditionalConfigData.keepAspectRatio = false;
m_sAdditionalConfigData.xray = -1;
m_sAdditionalConfigData.forceTearing = false;
m_sAdditionalConfigData.nearestNeighbor = false;
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
for (auto& r : WINDOWRULES) {
@@ -613,9 +674,9 @@ bool CWindow::isInCurvedCorner(double x, double y) {
void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) {
const auto DATA = (SExtensionFindingData*)data;
wlr_box box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height};
CBox box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height};
if (wlr_box_contains_point(&box, DATA->vec.x, DATA->vec.y))
if (box.containsPoint(DATA->vec))
*DATA->found = surface;
}
@@ -632,6 +693,69 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
return resultSurf;
}
void CWindow::applyGroupRules() {
if ((m_eGroupRules & GROUP_SET && m_bFirstMap) || m_eGroupRules & GROUP_SET_ALWAYS)
createGroup();
if (m_sGroupData.pNextWindow && ((m_eGroupRules & GROUP_LOCK && m_bFirstMap) || m_eGroupRules & GROUP_LOCK_ALWAYS))
getGroupHead()->m_sGroupData.locked = true;
}
void CWindow::createGroup() {
if (m_sGroupData.deny) {
Debug::log(LOG, "createGroup: window:{:x},title:{} is denied as a group, ignored", (uintptr_t)this, this->m_szTitle);
return;
}
if (!m_sGroupData.pNextWindow) {
m_sGroupData.pNextWindow = this;
m_sGroupData.head = true;
m_sGroupData.locked = false;
m_sGroupData.deny = false;
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(this));
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
}
}
void CWindow::destroyGroup() {
if (m_sGroupData.pNextWindow == this) {
if (m_eGroupRules & GROUP_SET_ALWAYS) {
Debug::log(LOG, "destoryGroup: window:{:x},title:{} has rule [group set always], ignored", (uintptr_t)this, this->m_szTitle);
return;
}
m_sGroupData.pNextWindow = nullptr;
updateWindowDecos();
return;
}
CWindow* curr = this;
std::vector<CWindow*> members;
do {
const auto PLASTWIN = curr;
curr = curr->m_sGroupData.pNextWindow;
PLASTWIN->m_sGroupData.pNextWindow = nullptr;
curr->setHidden(false);
members.push_back(curr);
} while (curr != this);
for (auto& w : members) {
if (w->m_sGroupData.head)
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr);
w->m_sGroupData.head = false;
}
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked;
g_pKeybindManager->m_bGroupsLocked = true;
for (auto& w : members) {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(w);
w->updateWindowDecos();
}
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
}
CWindow* CWindow::getGroupHead() {
CWindow* curr = this;
while (!curr->m_sGroupData.head)
@@ -653,6 +777,36 @@ CWindow* CWindow::getGroupCurrent() {
return curr;
}
int CWindow::getGroupSize() {
int size = 1;
CWindow* curr = this;
while (curr->m_sGroupData.pNextWindow != this) {
curr = curr->m_sGroupData.pNextWindow;
size++;
}
return size;
}
bool CWindow::canBeGroupedInto(CWindow* pWindow) {
return !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
&& ((m_eGroupRules & GROUP_INVADE && m_bFirstMap) // window ignore local group locks, or
|| (!pWindow->getGroupHead()->m_sGroupData.locked // target unlocked
&& !(m_sGroupData.pNextWindow && getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group
&& !m_sGroupData.deny // source is not denied entry
&& !(m_eGroupRules & GROUP_BARRED && m_bFirstMap); // group rule doesn't prevent adding window
}
CWindow* CWindow::getGroupWindowByIndex(int index) {
const int SIZE = getGroupSize();
index = ((index % SIZE) + SIZE) % SIZE;
CWindow* curr = getGroupHead();
while (index > 0) {
curr = curr->m_sGroupData.pNextWindow;
index--;
}
return curr;
}
void CWindow::setGroupCurrent(CWindow* pWindow) {
CWindow* curr = this->m_sGroupData.pNextWindow;
bool isMember = false;
@@ -698,13 +852,16 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode);
g_pHyprRenderer->damageWindow(pWindow);
pWindow->updateWindowDecos();
}
void CWindow::insertWindowToGroup(CWindow* pWindow) {
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("misc:group_insert_after_current")->intValue;
const auto BEGINAT = this;
const auto ENDAT = m_sGroupData.pNextWindow;
const auto BEGINAT = *USECURRPOS ? this : getGroupTail();
const auto ENDAT = *USECURRPOS ? m_sGroupData.pNextWindow : getGroupHead();
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
if (!pWindow->m_sGroupData.pNextWindow) {
BEGINAT->m_sGroupData.pNextWindow = pWindow;
@@ -780,6 +937,9 @@ bool CWindow::opaque() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall)
return false;
if (PWORKSPACE->m_fAlpha.fl() != 1.f)
return false;
@@ -831,3 +991,7 @@ int CWindow::getRealBorderSize() {
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
}
bool CWindow::canBeTorn() {
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
}

View File

@@ -1,7 +1,6 @@
#pragma once
#include "defines.hpp"
#include "events/Events.hpp"
#include "helpers/SubsurfaceTree.hpp"
#include "helpers/AnimatedVariable.hpp"
#include "render/decorations/IHyprWindowDecoration.hpp"
@@ -9,14 +8,32 @@
#include "config/ConfigDataValues.hpp"
#include "helpers/Vector2D.hpp"
#include "helpers/WLSurface.hpp"
#include "macros.hpp"
#include "managers/XWaylandManager.hpp"
enum eIdleInhibitMode {
enum eIdleInhibitMode
{
IDLEINHIBIT_NONE = 0,
IDLEINHIBIT_ALWAYS,
IDLEINHIBIT_FULLSCREEN,
IDLEINHIBIT_FOCUS
};
enum eGroupRules
{
// effective only during first map, except for _ALWAYS variant
GROUP_NONE = 0,
GROUP_SET = 1 << 0, // Open as new group or add to focused group
GROUP_SET_ALWAYS = 1 << 1,
GROUP_BARRED = 1 << 2, // Don't insert to focused group.
GROUP_LOCK = 1 << 3, // Lock m_sGroupData.lock
GROUP_LOCK_ALWAYS = 1 << 4,
GROUP_INVADE = 1 << 5, // Force enter a group, event if lock is engaged
GROUP_OVERRIDE = 1 << 6, // Override other rules
};
class IWindowTransformer;
template <typename T>
class CWindowOverridableVar {
public:
@@ -125,6 +142,8 @@ struct SWindowAdditionalConfigData {
CWindowOverridableVar<bool> keepAspectRatio = false;
CWindowOverridableVar<int> xray = -1; // -1 means unset, takes precedence over the renderdata one
CWindowOverridableVar<int> borderSize = -1; // -1 means unset, takes precedence over the renderdata one
CWindowOverridableVar<bool> forceTearing = false;
CWindowOverridableVar<bool> nearestNeighbor = false;
};
struct SWindowRule {
@@ -166,6 +185,7 @@ class CWindow {
DYNLISTENER(setOverrideRedirect);
DYNLISTENER(associateX11);
DYNLISTENER(dissociateX11);
DYNLISTENER(ackConfigure);
// DYNLISTENER(newSubsurfaceWindow);
CWLSurface m_pWLSurface;
@@ -185,8 +205,11 @@ class CWindow {
CAnimatedVariable m_vRealSize;
// for not spamming the protocols
Vector2D m_vReportedPosition;
Vector2D m_vReportedSize;
Vector2D m_vReportedPosition;
Vector2D m_vReportedSize;
Vector2D m_vPendingReportedSize;
std::optional<std::pair<uint32_t, Vector2D>> m_pPendingSizeAck;
std::vector<std::pair<uint32_t, Vector2D>> m_vPendingSizeAcks;
// for restoring floating statuses
Vector2D m_vLastFloatingSize;
@@ -273,6 +296,9 @@ class CWindow {
SWindowSpecialRenderData m_sSpecialRenderData;
SWindowAdditionalConfigData m_sAdditionalConfigData;
// Transformers
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
// for alpha
CAnimatedVariable m_fActiveInactiveAlpha;
@@ -299,8 +325,12 @@ class CWindow {
struct SGroupData {
CWindow* pNextWindow = nullptr; // nullptr means no grouping. Self means single group.
bool head = false;
bool locked = false;
bool locked = false; // per group lock
bool deny = false; // deny window from enter a group or made a group
} m_sGroupData;
uint16_t m_eGroupRules = GROUP_NONE;
bool m_bTearingHint = false;
// For the list lookup
bool operator==(const CWindow& rhs) {
@@ -309,11 +339,14 @@ class CWindow {
}
// methods
wlr_box getFullWindowBoundingBox();
CBox getFullWindowBoundingBox();
SWindowDecorationExtents getFullWindowExtents();
wlr_box getWindowInputBox();
wlr_box getWindowIdealBoundingBoxIgnoreReserved();
CBox getWindowInputBox();
CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco);
pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType);
void removeDecorationByType(eDecorationType);
@@ -333,6 +366,7 @@ class CWindow {
Vector2D middle();
bool opaque();
float rounding();
bool canBeTorn();
int getRealBorderSize();
void updateSpecialRenderData();
@@ -341,10 +375,16 @@ class CWindow {
bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos);
void applyGroupRules();
void createGroup();
void destroyGroup();
CWindow* getGroupHead();
CWindow* getGroupTail();
CWindow* getGroupCurrent();
CWindow* getGroupPrevious();
CWindow* getGroupWindowByIndex(int);
int getGroupSize();
bool canBeGroupedInto(CWindow* pWindow);
void setGroupCurrent(CWindow* pWindow);
void insertWindowToGroup(CWindow* pWindow);
void updateGroupOutputs();
@@ -354,3 +394,44 @@ class CWindow {
// For hidden windows and stuff
bool m_bHidden = false;
};
/**
format specification
- 'x', only address, equivalent of (uintpr_t)CWindow*
- 'm', with monitor id
- 'w', with workspace id
- 'c', with application class
*/
template <typename CharT>
struct std::formatter<CWindow*, CharT> : std::formatter<CharT> {
bool formatAddressOnly = false;
bool formatWorkspace = false;
bool formatMonitor = false;
bool formatClass = false;
FORMAT_PARSE( //
FORMAT_FLAG('x', formatAddressOnly) //
FORMAT_FLAG('m', formatMonitor) //
FORMAT_FLAG('w', formatWorkspace) //
FORMAT_FLAG('c', formatClass),
CWindow*)
template <typename FormatContext>
auto format(CWindow* const& w, FormatContext& ctx) const {
auto&& out = ctx.out();
if (formatAddressOnly)
return std::format_to(out, "{:x}", (uintptr_t)w);
if (!w)
return std::format_to(out, "[Window nullptr]");
std::format_to(out, "[");
std::format_to(out, "Window {:x}: title: \"{}\"", (uintptr_t)w, w->m_szTitle);
if (formatWorkspace)
std::format_to(out, ", workspace: {}", w->m_iWorkspaceID);
if (formatMonitor)
std::format_to(out, ", monitor: {}", w->m_iMonitorID);
if (formatClass)
std::format_to(out, ", class: {}", g_pXWaylandManager->getAppIDClass(w));
return std::format_to(out, "]");
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -11,16 +11,16 @@
#include <algorithm>
#include <regex>
#include <optional>
#include <functional>
#include <xf86drmMode.h>
#include "../Window.hpp"
#include "../helpers/WLClasses.hpp"
#include "../helpers/Monitor.hpp"
#include "../helpers/VarList.hpp"
#include "defaultConfig.hpp"
#include "ConfigDataValues.hpp"
#define STRVAL_EMPTY "[[EMPTY]]"
#define INITANIMCFG(name) animationConfig[name] = {}
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
@@ -37,18 +37,21 @@ struct SConfigValue {
};
struct SWorkspaceRule {
std::string monitor = "";
std::string workspaceString = "";
std::string workspaceName = "";
int workspaceId = -1;
bool isDefault = false;
std::optional<int64_t> gapsIn;
std::optional<int64_t> gapsOut;
std::optional<int64_t> borderSize;
std::optional<int> border;
std::optional<int> rounding;
std::optional<int> decorate;
std::optional<int> shadow;
std::string monitor = "";
std::string workspaceString = "";
std::string workspaceName = "";
int workspaceId = -1;
bool isDefault = false;
bool isPersistent = false;
std::optional<int64_t> gapsIn;
std::optional<int64_t> gapsOut;
std::optional<int64_t> borderSize;
std::optional<int> border;
std::optional<int> rounding;
std::optional<int> decorate;
std::optional<int> shadow;
std::optional<std::string> onCreatedEmptyRunCmd;
std::map<std::string, std::any> layoutopts;
};
struct SMonitorAdditionalReservedArea {
@@ -70,78 +73,17 @@ struct SAnimationPropertyConfig {
SAnimationPropertyConfig* pParentAnimation = nullptr;
};
struct SPluginKeyword {
HANDLE handle = 0;
std::string name = "";
std::function<void(const std::string&, const std::string&)> fn;
};
struct SExecRequestedRule {
std::string szRule = "";
uint64_t iPid = 0;
};
class CVarList {
public:
/* passing 's' as a separator will use std::isspace */
CVarList(const std::string& in, long unsigned int lastArgNo = 0, const char separator = ',') {
std::string curitem = "";
std::string argZ = in;
const bool SPACESEP = separator == 's';
auto nextItem = [&]() {
auto idx = lastArgNo != 0 && m_vArgs.size() >= lastArgNo - 1 ? std::string::npos : ([&]() -> size_t {
if (!SPACESEP)
return argZ.find_first_of(separator);
uint64_t pos = -1;
while (!std::isspace(argZ[++pos]) && pos < argZ.length())
;
return pos < argZ.length() ? pos : std::string::npos;
}());
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;
size_t 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];
}
// for range-based loops
std::vector<std::string>::iterator begin() {
return m_vArgs.begin();
}
std::vector<std::string>::const_iterator begin() const {
return m_vArgs.begin();
}
std::vector<std::string>::iterator end() {
return m_vArgs.end();
}
std::vector<std::string>::const_iterator end() const {
return m_vArgs.end();
}
private:
std::vector<std::string> m_vArgs;
};
class CConfigManager {
public:
CConfigManager();
@@ -151,14 +93,17 @@ class CConfigManager {
int getInt(const std::string&);
float getFloat(const std::string&);
Vector2D getVec(const std::string&);
std::string getString(const std::string&);
void setFloat(const std::string&, float);
void setInt(const std::string&, int);
void setVec(const std::string&, Vector2D);
void setString(const std::string&, const std::string&);
int getDeviceInt(const std::string&, const std::string&, std::optional<bool> touchpad = {});
float getDeviceFloat(const std::string&, const std::string&, std::optional<bool> touchpad = {});
std::string getDeviceString(const std::string&, const std::string&, std::optional<bool> touchpad = {});
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
bool deviceConfigExists(const std::string&);
bool shouldBlurLS(const std::string&);
@@ -183,7 +128,8 @@ class CConfigManager {
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
void removePluginConfig(HANDLE handle);
void addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& cmd, const std::string& val)> fun);
void removePluginConfig(HANDLE handle);
// no-op when done.
void dispatchExecOnce();
@@ -226,6 +172,7 @@ class CConfigManager {
std::vector<std::string> m_vDeclaredPlugins;
std::unordered_map<HANDLE, std::unique_ptr<std::unordered_map<std::string, SConfigValue>>> pluginConfigs; // stores plugin configs
std::vector<SPluginKeyword> pluginKeywords;
bool isFirstLaunch = true; // For exec-once
@@ -255,7 +202,7 @@ class CConfigManager {
void applyUserDefinedVars(std::string&, const size_t);
void loadConfigLoadVars();
SConfigValue getConfigValueSafe(const std::string&);
SConfigValue getConfigValueSafeDevice(const std::string&, const std::string&, std::optional<bool> touchpad);
SConfigValue getConfigValueSafeDevice(const std::string&, const std::string&, const std::string& fallback = "");
void parseLine(std::string&);
void configSetValueSafe(const std::string&, const std::string&);
void handleDeviceConfig(const std::string&, const std::string&);

View File

@@ -28,6 +28,11 @@ monitor=,preferred,auto,auto
# Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf
# Set programs that you use
$terminal = kitty
$fileManager = dolphin
$menu = wofi --show drun
# Some default env vars.
env = XCURSOR_SIZE,24
@@ -58,6 +63,9 @@ general {
col.inactive_border = rgba(595959aa)
layout = dwindle
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = false
}
decoration {
@@ -108,6 +116,11 @@ gestures {
workspace_swipe = off
}
misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
}
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
device:epic-mouse-v1 {
@@ -119,18 +132,19 @@ device:epic-mouse-v1 {
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
$mainMod = SUPER
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind = $mainMod, Q, exec, kitty
bind = $mainMod, Q, exec, $terminal
bind = $mainMod, C, killactive,
bind = $mainMod, M, exit,
bind = $mainMod, E, exec, dolphin
bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating,
bind = $mainMod, R, exec, wofi --show drun
bind = $mainMod, R, exec, $menu
bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, togglesplit, # dwindle
@@ -164,6 +178,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
# Example special workspace (scratchpad)
bind = $mainMod, S, togglespecialworkspace, magic
bind = $mainMod SHIFT, S, movetoworkspace, special:magic
# Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1

View File

@@ -1,7 +1,6 @@
#include "CrashReporter.hpp"
#include <random>
#include <sys/utsname.h>
#include <execinfo.h>
#include <fstream>
#include <signal.h>
@@ -14,19 +13,19 @@
std::string getRandomMessage() {
const std::vector<std::string> MESSAGES = {"Sorry, didn't mean to...",
"This was an accident, I swear!",
"Calm down, it was a misinput! MISINPUT!",
"Oops",
"Vaxry is going to be upset.",
"Who tried dividing by zero?!",
"Maybe you should try dusting your PC in the meantime?",
"I tried so hard, and got so far...",
"I don't feel so good...",
"*thud*",
"Well this is awkward.",
"\"stable\"",
"I hope you didn't have any unsaved progress.",
"All these computers..."};
"This was an accident, I swear!",
"Calm down, it was a misinput! MISINPUT!",
"Oops",
"Vaxry is going to be upset.",
"Who tried dividing by zero?!",
"Maybe you should try dusting your PC in the meantime?",
"I tried so hard, and got so far...",
"I don't feel so good...",
"*thud*",
"Well this is awkward.",
"\"stable\"",
"I hope you didn't have any unsaved progress.",
"All these computers..."};
std::random_device dev;
std::mt19937 engine(dev());
@@ -45,15 +44,15 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n";
finalCrashReport += getRandomMessage() + "\n\n";
finalCrashReport += getFormat("Hyprland received signal %d (%s)\n\n", sig, strsignal(sig));
finalCrashReport += std::format("Hyprland received signal {} ({})\n\n", sig, (const char*)strsignal(sig));
finalCrashReport += getFormat("Version: %s\nTag: %s\n\n", GIT_COMMIT_HASH, GIT_TAG);
finalCrashReport += std::format("Version: {}\nTag: {}\n\n", GIT_COMMIT_HASH, GIT_TAG);
if (g_pPluginSystem && !g_pPluginSystem->getAllPlugins().empty()) {
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
for (auto& p : g_pPluginSystem->getAllPlugins()) {
finalCrashReport += getFormat("\t%s (%s) %s\n", p->name.c_str(), p->author.c_str(), p->version.c_str());
finalCrashReport += std::format("\t{} ({}) {}\n", p->name, p->author, p->version);
}
finalCrashReport += "\n\n";
@@ -65,7 +64,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
uname(&unameInfo);
finalCrashReport +=
getFormat("\tSystem name: %s\n\tNode name: %s\n\tRelease: %s\n\tVersion: %s\n\n", unameInfo.sysname, unameInfo.nodename, unameInfo.release, unameInfo.version);
std::format("\tSystem name: {}\n\tNode name: {}\n\tRelease: {}\n\tVersion: {}\n\n", unameInfo.sysname, unameInfo.nodename, unameInfo.release, unameInfo.version);
#if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
@@ -75,7 +74,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "GPU:\n\t" + GPUINFO;
finalCrashReport += getFormat("\n\nos-release:\n\t%s\n\n\n", replaceInString(execAndGet("cat /etc/os-release"), "\n", "\n\t").c_str());
finalCrashReport += std::format("\n\nos-release:\n\t{}\n\n\n", replaceInString(execAndGet("cat /etc/os-release"), "\n", "\n\t"));
finalCrashReport += "Backtrace:\n";
@@ -107,12 +106,12 @@ void CrashReporter::createAndSaveCrash(int sig) {
#endif
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
finalCrashReport += getFormat("\t#%lu | %s\n", i, CALLSTACK[i].desc.c_str());
finalCrashReport += std::format("\t#{} | {}\n", i, CALLSTACK[i].desc);
#ifdef __clang__
const auto CMD = getFormat("llvm-addr2line -e %s -f 0x%lx", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
const auto CMD = std::format("llvm-addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
#else
const auto CMD = getFormat("addr2line -e %s -f 0x%lx", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
const auto CMD = std::format("addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
#endif
const auto ADDR2LINE = replaceInString(execAndGet(CMD.c_str()), "\n", "\n\t\t");
finalCrashReport += "\t\t" + ADDR2LINE.substr(0, ADDR2LINE.length() - 2);
@@ -120,7 +119,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "\n\nLog tail:\n";
finalCrashReport += execAndGet(("cat \"" + Debug::logFile + "\" | tail -n 50").c_str());
finalCrashReport += Debug::rollingLog;
const auto HOME = getenv("HOME");
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
@@ -130,7 +129,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
std::ofstream ofs;
std::string path;
if (!CACHE_HOME) {
if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
@@ -139,7 +138,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc);
} else if (CACHE_HOME) {
} else {
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) {
std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
std::filesystem::permissions(std::string(CACHE_HOME) + "/hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
@@ -147,8 +146,6 @@ void CrashReporter::createAndSaveCrash(int sig) {
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc);
} else {
return;
}
ofs << finalCrashReport;
@@ -156,5 +153,5 @@ void CrashReporter::createAndSaveCrash(int sig) {
ofs.close();
Debug::disableStdout = false;
Debug::log(CRIT, "Hyprland has crashed :( Consult the crash report at %s for more information.", path.c_str());
Debug::log(CRIT, "Hyprland has crashed :( Consult the crash report at {} for more information.", path);
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,8 @@ namespace HyprCtl {
inline int iSocketFD = -1;
enum eHyprCtlOutputFormat {
enum eHyprCtlOutputFormat
{
FORMAT_NORMAL = 0,
FORMAT_JSON
};

View File

@@ -132,7 +132,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
yOffset += 17;
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
text = std::string(getFormat("%i FPS", (int)FPS));
text = std::format("{} FPS", (int)FPS);
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
if (cairoExtents.width > maxX)
@@ -143,7 +143,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
yOffset += 11;
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
text = std::string(getFormat("Avg Frametime: %.2fms (var %.2fms)", avgFrametime, varFrametime));
text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime);
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
if (cairoExtents.width > maxX)
@@ -151,7 +151,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
yOffset += 11;
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
text = std::string(getFormat("Avg Rendertime: %.2fms (var %.2fms)", avgRenderTime, varRenderTime));
text = std::format("Avg Rendertime: {:.2f}ms (var {:.2f}ms)", avgRenderTime, varRenderTime);
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
if (cairoExtents.width > maxX)
@@ -159,7 +159,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
yOffset += 11;
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
text = std::string(getFormat("Avg Rendertime (No Overlay): %.2fms (var %.2fms)", avgRenderTimeNoOverlay, varRenderTimeNoOverlay));
text = std::format("Avg Rendertime (No Overlay): {:.2f}ms (var {:.2f}ms)", avgRenderTimeNoOverlay, varRenderTimeNoOverlay);
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
if (cairoExtents.width > maxX)
@@ -167,7 +167,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
yOffset += 11;
cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset);
text = std::string(getFormat("Avg Anim Tick: %.2fms (var %.2fms) (%.2f TPS)", avgAnimMgrTick, varAnimMgrTick, 1.0 / (avgAnimMgrTick / 1000.0)));
text = std::format("Avg Anim Tick: {:.2f}ms (var {:.2f}ms) ({:.2f} TPS)", avgAnimMgrTick, varAnimMgrTick, 1.0 / (avgAnimMgrTick / 1000.0));
cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str());
cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents);
if (cairoExtents.width > maxX)
@@ -233,6 +233,6 @@ void CHyprDebugOverlay::draw() {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
wlr_box pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
}

View File

@@ -24,7 +24,7 @@ class CHyprMonitorDebugOverlay {
std::deque<float> m_dLastAnimationTicks;
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
CMonitor* m_pMonitor = nullptr;
wlr_box m_wbLastDrawnBox;
CBox m_wbLastDrawnBox;
friend class CHyprRenderer;
};

View File

@@ -3,7 +3,7 @@
#include <pango/pangocairo.h>
CHyprNotificationOverlay::CHyprNotificationOverlay() {
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, std::any param) {
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (m_dNotifications.size() == 0)
return;
@@ -44,9 +44,13 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC
PNOTIF->started.reset();
PNOTIF->timeMs = timeMs;
PNOTIF->icon = icon;
for (auto& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m.get());
}
}
wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
static constexpr auto ANIM_DURATION_MS = 600.0;
static constexpr auto ANIM_LAG_MS = 100.0;
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
@@ -166,7 +170,7 @@ wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
// cleanup notifs
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
return wlr_box{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
}
void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
@@ -197,7 +201,7 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
cairo_surface_flush(m_pCairoSurface);
wlr_box damage = drawNotifications(pMonitor);
CBox damage = drawNotifications(pMonitor);
g_pHyprRenderer->damageBox(&damage);
g_pHyprRenderer->damageBox(&m_bLastDamage);
@@ -220,6 +224,6 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
wlr_box pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
CBox pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
}

View File

@@ -44,8 +44,8 @@ class CHyprNotificationOverlay {
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
private:
wlr_box drawNotifications(CMonitor* pMonitor);
wlr_box m_bLastDamage;
CBox drawNotifications(CMonitor* pMonitor);
CBox m_bLastDamage;
std::deque<std::unique_ptr<SNotification>> m_dNotifications;

View File

@@ -10,78 +10,25 @@ void Debug::init(const std::string& IS) {
}
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
char* outputStr = nullptr;
if (level > wlr_log_get_verbosity())
return;
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
char* outputStr = nullptr;
vasprintf(&outputStr, fmt, args);
std::string output = std::string(outputStr);
free(outputStr);
ofs << "[wlr] " << output << "\n";
rollingLog += output + "\n";
ofs.close();
if (!disableLogs || !*disableLogs) {
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
ofs << "[wlr] " << output << "\n";
ofs.close();
}
if (!disableStdout)
std::cout << output << "\n";
}
void Debug::log(LogLevel level, const char* fmt, ...) {
if (disableLogs && *disableLogs)
return;
if (level == TRACE && !trace)
return;
// log to a file
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
switch (level) {
case LOG: ofs << "[LOG] "; break;
case WARN: ofs << "[WARN] "; break;
case ERR: ofs << "[ERR] "; break;
case CRIT: ofs << "[CRITICAL] "; break;
case INFO: ofs << "[INFO] "; break;
case TRACE: ofs << "[TRACE] "; break;
default: break;
}
// print date and time to the ofs
if (disableTime && !*disableTime) {
auto timet = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
const auto MILLIS = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() % 1000;
ofs << std::put_time(std::localtime(&timet), "[%H:%M:%S:");
if (MILLIS > 99)
ofs << MILLIS;
else if (MILLIS > 9)
ofs << "0" << MILLIS;
else
ofs << "00" << MILLIS;
ofs << "] ";
}
char* outputStr = nullptr;
va_list args;
va_start(args, fmt);
vasprintf(&outputStr, fmt, args);
va_end(args);
std::string output = std::string(outputStr);
free(outputStr);
ofs << output << "\n";
ofs.close();
// log it to the stdout too.
if (!disableStdout)
std::cout << output << "\n";
}

View File

@@ -1,10 +1,17 @@
#pragma once
#include <string>
#include <wlr/util/log.h>
#include <format>
#include <iostream>
#include <fstream>
#include <chrono>
#include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp"
#define LOGMESSAGESIZE 1024
#define LOGMESSAGESIZE 1024
#define ROLLING_LOG_SIZE 4096
enum LogLevel {
enum LogLevel
{
NONE = -1,
LOG = 0,
WARN,
@@ -15,13 +22,67 @@ enum LogLevel {
};
namespace Debug {
void init(const std::string& IS);
void log(LogLevel level, const char* fmt, ...);
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
inline std::string logFile;
inline int64_t* disableLogs = nullptr;
inline int64_t* disableTime = nullptr;
inline bool disableStdout = false;
inline bool trace = false;
};
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
void init(const std::string& IS);
template <typename... Args>
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
if (level == TRACE && !trace)
return;
std::string logMsg = "";
switch (level) {
case LOG: logMsg += "[LOG] "; break;
case WARN: logMsg += "[WARN] "; break;
case ERR: logMsg += "[ERR] "; break;
case CRIT: logMsg += "[CRITICAL] "; break;
case INFO: logMsg += "[INFO] "; break;
case TRACE: logMsg += "[TRACE] "; break;
default: break;
}
// print date and time to the ofs
if (disableTime && !*disableTime) {
#ifndef _LIBCPP_VERSION
logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())});
#else
auto c = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())};
logMsg += std::format("{:%H}:{:%M}:{:%S}", c.hours(), c.minutes(), c.subseconds());
#endif
}
// no need for try {} catch {} because std::format_string<Args...> ensures that vformat never throw std::format_error
// because
// 1. any faulty format specifier that sucks will cause a compilation error.
// 2. and `std::bad_alloc` is catastrophic, (Almost any operation in stdlib could throw this.)
// 3. this is actually what std::format in stdlib does
logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
rollingLog += logMsg + "\n";
if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
if (!disableLogs || !*disableLogs) {
// log to a file
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
ofs << logMsg << "\n";
ofs.close();
}
// log it to the stdout too.
if (!disableStdout)
std::cout << logMsg << "\n";
}
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
};

View File

@@ -13,15 +13,6 @@ inline PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v;
#include "../../subprojects/tracy/public/tracy/TracyOpenGL.hpp"
inline void loadGLProc(void* pProc, const char* name) {
void* proc = (void*)eglGetProcAddress(name);
if (proc == NULL) {
Debug::log(CRIT, "[Tracy GPU Profiling] eglGetProcAddress(%s) failed", name);
abort();
}
*(void**)pProc = proc;
}
#define TRACY_GPU_CONTEXT TracyGpuContext
#define TRACY_GPU_ZONE(e) TracyGpuZone(e)
#define TRACY_GPU_COLLECT TracyGpuCollect

View File

@@ -19,7 +19,7 @@ void Events::listener_keyboardDestroy(void* owner, void* data) {
SKeyboard* PKEYBOARD = (SKeyboard*)owner;
g_pInputManager->destroyKeyboard(PKEYBOARD);
Debug::log(LOG, "Destroyed keyboard %lx", PKEYBOARD);
Debug::log(LOG, "Destroyed keyboard {:x}", (uintptr_t)PKEYBOARD);
}
void Events::listener_keyboardKey(void* owner, void* data) {
@@ -63,30 +63,30 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
switch (DEVICE->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
Debug::log(LOG, "Attached a keyboard with name %s", DEVICE->name);
Debug::log(LOG, "Attached a keyboard with name {}", DEVICE->name);
g_pInputManager->newKeyboard(DEVICE);
break;
case WLR_INPUT_DEVICE_POINTER:
Debug::log(LOG, "Attached a mouse with name %s", DEVICE->name);
Debug::log(LOG, "Attached a mouse with name {}", DEVICE->name);
g_pInputManager->newMouse(DEVICE);
break;
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 {}", DEVICE->name);
g_pInputManager->newTouchDevice(DEVICE);
break;
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 {}", DEVICE->name);
g_pInputManager->newTabletTool(DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET_PAD:
Debug::log(LOG, "Attached a tablet pad with name %s", DEVICE->name);
Debug::log(LOG, "Attached a tablet pad with name {}", DEVICE->name);
g_pInputManager->newTabletPad(DEVICE);
break;
case WLR_INPUT_DEVICE_SWITCH:
Debug::log(LOG, "Attached a switch device with name %s", DEVICE->name);
Debug::log(LOG, "Attached a switch device with name {}", DEVICE->name);
g_pInputManager->newSwitch(DEVICE);
break;
default: Debug::log(WARN, "Unrecognized input device plugged in: %s", DEVICE->name); break;
default: Debug::log(WARN, "Unrecognized input device plugged in: {}", DEVICE->name); break;
}
g_pInputManager->updateCapabilities();
@@ -95,7 +95,7 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
void Events::listener_newConstraint(wl_listener* listener, void* data) {
const auto PCONSTRAINT = (wlr_pointer_constraint_v1*)data;
Debug::log(LOG, "New mouse constraint at %lx", PCONSTRAINT);
Debug::log(LOG, "New mouse constraint at {:x}", (uintptr_t)PCONSTRAINT);
g_pInputManager->m_lConstraints.emplace_back();
const auto CONSTRAINT = &g_pInputManager->m_lConstraints.back();
@@ -122,13 +122,13 @@ void Events::listener_destroyConstraint(void* owner, void* data) {
const auto PWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
if (PWINDOW && PCONSTRAINT->positionHint != Vector2D{-1, -1})
if (PWINDOW && PCONSTRAINT->active && PCONSTRAINT->constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
g_pInputManager->warpMouseToConstraintMiddle(PCONSTRAINT);
PCONSTRAINT->pMouse->currentConstraint = nullptr;
}
Debug::log(LOG, "Unconstrained mouse from %lx", PCONSTRAINT->constraint);
Debug::log(LOG, "Unconstrained mouse from {:x}", (uintptr_t)PCONSTRAINT->constraint);
g_pInputManager->m_lConstraints.remove(*PCONSTRAINT);
}

View File

@@ -42,7 +42,7 @@ namespace Events {
DYNLISTENFUNC(repositionPopupXDG);
// Surface XDG (window)
LISTENER(newXDGSurface);
LISTENER(newXDGToplevel);
LISTENER(activateXDG);
// Window events
@@ -62,6 +62,7 @@ namespace Events {
DYNLISTENFUNC(setOverrideRedirect);
DYNLISTENFUNC(associateX11);
DYNLISTENFUNC(dissociateX11);
DYNLISTENFUNC(ackConfigure);
// Window subsurfaces
// LISTENER(newSubsurfaceWindow);
@@ -120,10 +121,6 @@ namespace Events {
DYNLISTENFUNC(destroyDragIcon);
DYNLISTENFUNC(commitDragIcon);
// Inhibit
LISTENER(InhibitActivate);
LISTENER(InhibitDeactivate);
// Deco XDG
LISTENER(NewXDGDeco);
@@ -174,4 +171,7 @@ namespace Events {
// Cursor shape
LISTENER(setCursorShape);
// Tearing hints
LISTENER(newTearingHint);
};

View File

@@ -26,7 +26,7 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
return;
}
Debug::log(LOG, "New LayerSurface has no preferred monitor. Assigning Monitor %s", PMONITOR->szName.c_str());
Debug::log(LOG, "New LayerSurface has no preferred monitor. Assigning Monitor {}", PMONITOR->szName);
WLRLAYERSURFACE->output = PMONITOR->output;
}
@@ -55,14 +55,14 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
layerSurface->forceBlur = g_pConfigManager->shouldBlurLS(layerSurface->szNamespace);
Debug::log(LOG, "LayerSurface %lx (namespace %s layer %d) created on monitor %s", layerSurface->layerSurface, layerSurface->layerSurface->_namespace, layerSurface->layer,
PMONITOR->szName.c_str());
Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)layerSurface->layerSurface, layerSurface->layerSurface->_namespace,
(int)layerSurface->layer, PMONITOR->szName);
}
void Events::listener_destroyLayerSurface(void* owner, void* data) {
SLayerSurface* layersurface = (SLayerSurface*)owner;
Debug::log(LOG, "LayerSurface %lx destroyed", layersurface->layerSurface);
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layersurface->layerSurface);
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
@@ -95,8 +95,8 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
PMONITOR->scheduledRecalc = true;
// and damage
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
}
@@ -107,7 +107,7 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
void Events::listener_mapLayerSurface(void* owner, void* data) {
SLayerSurface* layersurface = (SLayerSurface*)owner;
Debug::log(LOG, "LayerSurface %lx mapped", layersurface->layerSurface);
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layersurface->layerSurface);
layersurface->mapped = true;
layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive;
@@ -142,7 +142,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive &&
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
@@ -157,8 +157,8 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
@@ -171,13 +171,14 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
EMIT_HOOK_EVENT("openLayer", layersurface);
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
}
void Events::listener_unmapLayerSurface(void* owner, void* data) {
SLayerSurface* layersurface = (SLayerSurface*)owner;
Debug::log(LOG, "LayerSurface %lx unmapped", layersurface->layerSurface);
Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layersurface->layerSurface);
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
EMIT_HOOK_EVENT("closeLayer", layersurface);
@@ -246,13 +247,15 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
}
}
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y,
(int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
g_pHyprRenderer->damageBox(&geomFixed);
g_pInputManager->simulateMouseMovement();
}
void Events::listener_commitLayerSurface(void* owner, void* data) {
@@ -269,7 +272,7 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
if (layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
wlr_box geomFixed = {layersurface->geometry.x, layersurface->geometry.y, layersurface->geometry.width, layersurface->geometry.height};
CBox geomFixed = {layersurface->geometry.x, layersurface->geometry.y, layersurface->geometry.width, layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
// fix if it changed its mon
@@ -342,5 +345,6 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y);
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
}

View File

@@ -49,7 +49,7 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL);
const auto ERR = xcb_connection_has_error(XCBCONNECTION);
if (ERR) {
Debug::log(LogLevel::ERR, "XWayland -> xcb_connection_has_error failed with %i", ERR);
Debug::log(LogLevel::ERR, "XWayland -> xcb_connection_has_error failed with {}", ERR);
return;
}
@@ -58,7 +58,7 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(XCBCONNECTION, cookie, NULL);
if (!reply) {
Debug::log(LogLevel::ERR, "XWayland -> Atom failed: %s", ATOM.first.c_str());
Debug::log(LogLevel::ERR, "XWayland -> Atom failed: {}", ATOM.first);
continue;
}
@@ -98,14 +98,14 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
wlr_drag* wlrDrag = (wlr_drag*)data;
Debug::log(LOG, "Started drag %lx", wlrDrag);
Debug::log(LOG, "Started drag {:x}", (uintptr_t)wlrDrag);
wlrDrag->data = data;
g_pInputManager->m_sDrag.hyprListener_destroy.initCallback(&wlrDrag->events.destroy, &Events::listener_destroyDrag, &g_pInputManager->m_sDrag, "Drag");
if (wlrDrag->icon) {
Debug::log(LOG, "Drag started with an icon %lx", wlrDrag->icon);
Debug::log(LOG, "Drag started with an icon {:x}", (uintptr_t)wlrDrag->icon);
g_pInputManager->m_sDrag.dragIcon = wlrDrag->icon;
wlrDrag->icon->data = g_pInputManager->m_sDrag.dragIcon;
@@ -156,20 +156,6 @@ void Events::listener_commitDragIcon(void* owner, void* data) {
Debug::log(LOG, "Drag icon committed.");
}
void Events::listener_InhibitActivate(wl_listener* listener, void* data) {
Debug::log(LOG, "Activated exclusive for %lx.", g_pCompositor->m_sSeat.exclusiveClient);
g_pInputManager->refocus();
g_pCompositor->m_sSeat.exclusiveClient = g_pCompositor->m_sWLRInhibitMgr->active_client;
}
void Events::listener_InhibitDeactivate(wl_listener* listener, void* data) {
Debug::log(LOG, "Deactivated exclusive.");
g_pCompositor->m_sSeat.exclusiveClient = nullptr;
g_pInputManager->refocus();
}
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
Debug::log(LOG, "!!Renderer destroyed!!");
}
@@ -216,14 +202,14 @@ void Events::listener_newSessionLock(wl_listener* listener, void* data) {
}
void Events::listener_setGamma(wl_listener* listener, void* data) {
Debug::log(LOG, "New Gamma event at %lx", data);
Debug::log(LOG, "New Gamma event at {:x}", (uintptr_t)data);
const auto E = (wlr_gamma_control_manager_v1_set_gamma_event*)data;
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(E->output);
if (!PMONITOR) {
Debug::log(ERR, "Gamma event object references non-existent output %lx ?", E->output);
Debug::log(ERR, "Gamma event object references non-existent output {:x} ?", (uintptr_t)E->output);
return;
}
@@ -237,3 +223,43 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
g_pInputManager->processMouseRequest(E);
}
void Events::listener_newTearingHint(wl_listener* listener, void* data) {
const auto TCTL = (wlr_tearing_control_v1*)data;
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface);
if (!PWINDOW) {
Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
return;
}
Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)data);
const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
NEWCTRL->hyprListener_destroy.initCallback(
&NEWCTRL->pWlrHint->events.destroy,
[&](void* owner, void* data) {
Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
},
NEWCTRL, "TearingController");
NEWCTRL->hyprListener_set.initCallback(
&NEWCTRL->pWlrHint->events.set_hint,
[&](void* owner, void* data) {
const auto TEARINGHINT = (STearingController*)owner;
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
if (PWINDOW) {
PWINDOW->m_bTearingHint = TEARINGHINT->pWlrHint->hint;
Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->hint);
}
},
NEWCTRL, "TearingController");
}

View File

@@ -22,14 +22,18 @@ void Events::listener_change(wl_listener* listener, void* data) {
if (!CONFIG)
return;
for (auto& m : g_pCompositor->m_vMonitors) {
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (!m->output)
continue;
if (g_pCompositor->m_pUnsafeOutput == m.get())
continue;
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output);
wlr_box BOX;
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, &BOX);
CBox BOX;
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, BOX.pWlr());
BOX.applyFromWlr();
//m->vecSize.x = BOX.width;
// m->vecSize.y = BOX.height;
@@ -38,8 +42,18 @@ void Events::listener_change(wl_listener* listener, void* data) {
CONFIGHEAD->state.enabled = m->output->enabled;
CONFIGHEAD->state.mode = m->output->current_mode;
CONFIGHEAD->state.x = m->vecPosition.x;
CONFIGHEAD->state.y = m->vecPosition.y;
if (!m->output->current_mode) {
CONFIGHEAD->state.custom_mode = {
m->output->width,
m->output->height,
m->output->refresh,
};
}
CONFIGHEAD->state.x = m->vecPosition.x;
CONFIGHEAD->state.y = m->vecPosition.y;
CONFIGHEAD->state.transform = m->transform;
CONFIGHEAD->state.scale = m->scale;
CONFIGHEAD->state.adaptive_sync_enabled = m->vrrActive;
}
wlr_output_manager_v1_set_configuration(g_pCompositor->m_sWLROutputMgr, CONFIG);
@@ -57,50 +71,38 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
return;
}
if (g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Recovering from an unsafe state. May you be lucky.");
}
// add it to real
std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
for (auto& rm : g_pCompositor->m_vRealMonitors) {
if (rm->szName == OUTPUT->name) {
PNEWMONITORWRAP = &rm;
Debug::log(LOG, "Recovering a removed monitor.");
break;
}
}
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
if (std::string("HEADLESS-1") == OUTPUT->name)
g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get();
if (!PNEWMONITORWRAP) {
Debug::log(LOG, "Adding completely new monitor.");
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
(*PNEWMONITORWRAP)->output = OUTPUT;
const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false;
(*PNEWMONITORWRAP)->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name);
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
PNEWMONITOR->isUnsafeFallback = FALLBACK;
(*PNEWMONITORWRAP)->ID = g_pCompositor->getNextAvailableMonitorID(OUTPUT->name);
}
if (!FALLBACK)
PNEWMONITOR->onConnect(false);
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
return;
PNEWMONITOR->output = OUTPUT;
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
PNEWMONITOR->onConnect(false);
// ready to process if we have a real monitor
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
// ready to process cuz we have a monitor
if (PNEWMONITOR->m_bEnabled) {
g_pCompositor->m_bReadyToProcess = true;
g_pCompositor->m_bUnsafeState = false;
}
g_pCompositor->m_bReadyToProcess = true;
g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
if (firstLaunch) {
firstLaunch = false;
const auto POS = PNEWMONITOR->vecPosition + PNEWMONITOR->vecSize / 2.f;
const auto POS = PNEWMONITOR->middle();
if (g_pCompositor->m_sSeat.mouse)
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, POS.x, POS.y);
} else {
@@ -119,8 +121,12 @@ void Events::listener_monitorFrame(void* owner, void* data) {
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!");
if (g_pCompositor->m_bUnsafeState)
g_pConfigManager->performMonitorReload();
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
return m->output != g_pCompositor->m_pUnsafeOutput->output;
})) {
// restore from unsafe state
g_pCompositor->leaveUnsafeState();
}
return; // cannot draw on session inactive (different tty)
}
@@ -128,12 +134,25 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (!PMONITOR->m_bEnabled)
return;
g_pHyprRenderer->recheckSolitaryForMonitor(PMONITOR);
PMONITOR->tearingState.busy = false;
if (PMONITOR->tearingState.activelyTearing && PMONITOR->solitaryClient /* can be invalidated by a recheck */) {
if (!PMONITOR->tearingState.frameScheduledWhileBusy)
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
PMONITOR->tearingState.nextRenderTorn = true;
PMONITOR->tearingState.frameScheduledWhileBusy = false;
}
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
PMONITOR->lastPresentationTimer.reset();
if (*PENABLERAT) {
if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
if (!PMONITOR->RATScheduled) {
// render
g_pHyprRenderer->renderMonitor(PMONITOR);
@@ -177,19 +196,16 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
if (!pMonitor)
return;
Debug::log(LOG, "Destroy called for monitor %s", pMonitor->output->name);
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
pMonitor->onDisconnect();
pMonitor->onDisconnect(true);
pMonitor->output = nullptr;
pMonitor->m_bRenderingInitPassed = false;
// cleanup if not unsafe
if (!g_pCompositor->m_bUnsafeState) {
Debug::log(LOG, "Removing monitor %s from realMonitors", pMonitor->szName.c_str());
Debug::log(LOG, "Removing monitor {} from realMonitors", pMonitor->szName);
std::erase_if(g_pCompositor->m_vRealMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; });
}
std::erase_if(g_pCompositor->m_vRealMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == pMonitor; });
}
void Events::listener_monitorStateRequest(void* owner, void* data) {
@@ -217,7 +233,7 @@ void Events::listener_monitorCommit(void* owner, void* data) {
const auto E = (wlr_output_event_commit*)data;
if (E->committed & WLR_OUTPUT_STATE_BUFFER) {
if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) {
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
}

View File

@@ -64,14 +64,13 @@ void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->vecSize.x, .height = PMONITOR->vecSize.y};
CBox box = {PMONITOR->vecPosition.x - pHyprPopup->lx, PMONITOR->vecPosition.y - pHyprPopup->ly, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(popup, &box);
wlr_xdg_popup_unconstrain_from_box(popup, box.pWlr());
pHyprPopup->monitor = PMONITOR;
Debug::log(LOG, "Popup: Unconstrained from lx ly: %f %f, pHyprPopup lx ly: %f %f", (float)PMONITOR->vecPosition.x, (float)PMONITOR->vecPosition.y, (float)pHyprPopup->lx,
(float)pHyprPopup->ly);
Debug::log(LOG, "Popup: Unconstrained from lx ly: {:j5}, pHyprPopup lx ly: {:.5f} {:.5f}", PMONITOR->vecPosition, (float)pHyprPopup->lx, (float)pHyprPopup->ly);
}
void Events::listener_newPopup(void* owner, void* data) {
@@ -79,7 +78,7 @@ void Events::listener_newPopup(void* owner, void* data) {
ASSERT(layersurface);
Debug::log(LOG, "New layer popup created from surface %lx", layersurface);
Debug::log(LOG, "New layer popup created from surface {:x}", (uintptr_t)layersurface);
const auto WLRPOPUP = (wlr_xdg_popup*)data;
@@ -103,7 +102,7 @@ void Events::listener_newPopupXDG(void* owner, void* data) {
if (!PWINDOW->m_bIsMapped)
return;
Debug::log(LOG, "New layer popup created from XDG window %lx -> %s", PWINDOW, PWINDOW->m_szTitle.c_str());
Debug::log(LOG, "New layer popup created from XDG window {}", PWINDOW);
const auto WLRPOPUP = (wlr_xdg_popup*)data;
@@ -125,9 +124,9 @@ void Events::listener_newPopupFromPopupXDG(void* owner, void* data) {
ASSERT(PPOPUP);
if (PPOPUP->parentWindow)
Debug::log(LOG, "New popup created from XDG Window popup %lx -> %s", PPOPUP, PPOPUP->parentWindow->m_szTitle.c_str());
Debug::log(LOG, "New popup created from XDG Window popup {:x} -> {}", (uintptr_t)PPOPUP, PPOPUP->parentWindow);
else
Debug::log(LOG, "New popup created from Non-Window popup %lx", PPOPUP);
Debug::log(LOG, "New popup created from Non-Window popup {:x}", (uintptr_t)PPOPUP);
const auto WLRPOPUP = (wlr_xdg_popup*)data;
@@ -148,7 +147,7 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
ASSERT(PPOPUP);
Debug::log(LOG, "New XDG Popup mapped at %d %d", (int)PPOPUP->lx, (int)PPOPUP->ly);
Debug::log(LOG, "New XDG Popup mapped at {} {}", (int)PPOPUP->lx, (int)PPOPUP->ly);
if (PPOPUP->parentWindow)
PPOPUP->parentWindow->m_lPopupSurfaces.emplace_back(PPOPUP->popup->base->surface);
@@ -160,30 +159,40 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
wlr_box extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
if (PPOPUP->monitor)
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale);
if (PPOPUP->monitor) {
g_pCompositor->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale);
g_pCompositor->setPreferredTransformForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->transform);
}
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %lx", PPOPUP->pSurfaceTree);
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree);
}
void Events::listener_repositionPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
Debug::log(LOG, "XDG Popup %lx asks for a reposition", PPOPUP);
Debug::log(LOG, "XDG Popup {:x} asks for a reposition", (uintptr_t)PPOPUP);
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
wlr_box extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
PPOPUP->lastPos = {lx - extents.x, ly - extents.y};
PPOPUP->repositionRequested = true;
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
CBox box = {PMONITOR->vecPosition.x - lx + PPOPUP->popup->current.geometry.x, PMONITOR->vecPosition.y - ly + PPOPUP->popup->current.geometry.y, PMONITOR->vecSize.x,
PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(PPOPUP->popup, box.pWlr());
}
void Events::listener_unmapPopupXDG(void* owner, void* data) {
@@ -200,8 +209,9 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
wlr_box extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
@@ -226,8 +236,9 @@ void Events::listener_commitPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
wlr_box extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
if (PPOPUP->repositionRequested)
g_pHyprRenderer->damageBox(PPOPUP->lastPos.x, PPOPUP->lastPos.y, extents.width + 2, extents.height + 2);
@@ -242,7 +253,7 @@ void Events::listener_destroyPopupXDG(void* owner, void* data) {
ASSERT(PPOPUP);
Debug::log(LOG, "Destroyed popup XDG %lx", PPOPUP);
Debug::log(LOG, "Destroyed popup XDG {:x}", (uintptr_t)PPOPUP);
if (PPOPUP->pSurfaceTree) {
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);

View File

@@ -46,6 +46,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
static auto* const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex")->strValue;
static auto* const PNEWTAKESOVERFS = &g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen")->intValue;
auto PMONITOR = g_pCompositor->m_pLastMonitor;
const auto PWORKSPACE =
@@ -95,7 +96,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PWORKSPACE->m_bDefaultPseudo) {
PWINDOW->m_bIsPseudotiled = true;
wlr_box desiredGeometry = {0};
CBox desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry);
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
}
@@ -111,14 +112,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
bool requestsMaximize = false;
bool overridingNoFullscreen = false;
bool overridingNoMaximize = false;
bool shouldFocus = true;
bool workspaceSpecial = false;
PWINDOW->m_szInitialTitle = g_pXWaylandManager->getTitle(PWINDOW);
PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW);
for (auto& r : WINDOWRULES) {
if (r.szRule.find("monitor") == 0) {
if (r.szRule.starts_with("monitor")) {
try {
const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' ')));
@@ -136,7 +135,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PMONITOR)
PWINDOW->m_iMonitorID = PMONITOR->ID;
else {
Debug::log(ERR, "No monitor in monitor %s rule", MONITORSTR.c_str());
Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
continue;
}
}
@@ -144,15 +143,15 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PMONITORFROMID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
if (PWINDOW->m_iMonitorID != PMONITOR->ID) {
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
PMONITOR = PMONITORFROMID;
}
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
Debug::log(ERR, "Rule monitor, applying to window %lx -> mon: %i, workspace: %i", PWINDOW, PWINDOW->m_iMonitorID, PWINDOW->m_iWorkspaceID);
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: %s -> %s | err: %s", r.szRule.c_str(), r.szValue.c_str(), e.what()); }
} else if (r.szRule.find("workspace") == 0) {
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
} else if (r.szRule.starts_with("workspace")) {
// check if it isnt unset
const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
@@ -167,20 +166,20 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (JUSTWORKSPACE == PWORKSPACE->m_szName || JUSTWORKSPACE == "name:" + PWORKSPACE->m_szName)
requestedWorkspace = "";
Debug::log(LOG, "Rule workspace matched by window %lx, %s applied.", PWINDOW, r.szValue.c_str());
} else if (r.szRule.find("float") == 0) {
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r.szValue);
} else if (r.szRule.starts_with("float")) {
PWINDOW->m_bIsFloating = true;
} else if (r.szRule.find("tile") == 0) {
} else if (r.szRule.starts_with("tile")) {
PWINDOW->m_bIsFloating = false;
} else if (r.szRule.find("pseudo") == 0) {
} else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.find("nofocus") == 0) {
} else if (r.szRule.starts_with("nofocus")) {
PWINDOW->m_bNoFocus = true;
} else if (r.szRule.find("noinitialfocus") == 0) {
} else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.find("nofullscreenrequest") == 0) {
} else if (r.szRule.starts_with("nofullscreenrequest")) {
PWINDOW->m_bNoFullscreenRequest = true;
} else if (r.szRule.find("nomaximizerequest") == 0) {
} else if (r.szRule.starts_with("nomaximizerequest")) {
PWINDOW->m_bNoMaximizeRequest = true;
} else if (r.szRule == "fullscreen") {
requestsFullscreen = true;
@@ -200,103 +199,94 @@ void Events::listener_mapWindow(void* owner, void* data) {
overridingNoMaximize = true;
} else if (r.szRule == "stayfocused") {
PWINDOW->m_bStayFocused = true;
} else if (r.szRule.find("idleinhibit") == 0) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
} else if (r.szRule.starts_with("group")) {
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
continue;
if (IDLERULE == "none") {
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_NONE;
} else if (IDLERULE == "always") {
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
} else if (IDLERULE == "focus") {
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
} else if (IDLERULE == "fullscreen") {
PWINDOW->m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
} else {
Debug::log(ERR, "Rule idleinhibit: unknown mode %s", IDLERULE.c_str());
// `group` is a shorthand of `group set`
if (removeBeginEndSpacesTabs(r.szRule) == "group") {
PWINDOW->m_eGroupRules |= GROUP_SET;
continue;
}
CVarList vars(r.szRule, 0, 's');
std::string vPrev = "";
for (auto const& v : vars) {
if (v == "group")
continue;
if (v == "set") {
PWINDOW->m_eGroupRules |= GROUP_SET;
} else if (v == "new") {
// shorthand for `group barred set`
PWINDOW->m_eGroupRules |= (GROUP_SET | GROUP_BARRED);
} else if (v == "lock") {
PWINDOW->m_eGroupRules |= GROUP_LOCK;
} else if (v == "invade") {
PWINDOW->m_eGroupRules |= GROUP_INVADE;
} else if (v == "barred") {
PWINDOW->m_eGroupRules |= GROUP_BARRED;
} else if (v == "deny") {
PWINDOW->m_sGroupData.deny = true;
} else if (v == "override") {
// Clear existing rules
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
} else if (v == "unset") {
// Clear existing rules and stop processing
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
break;
} else if (v == "always") {
if (vPrev == "set" || vPrev == "group")
PWINDOW->m_eGroupRules |= GROUP_SET_ALWAYS;
else if (vPrev == "lock")
PWINDOW->m_eGroupRules |= GROUP_LOCK_ALWAYS;
else
Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev);
}
vPrev = v;
}
}
PWINDOW->applyDynamicRule(r);
}
CWindow* pFullscreenWindow = nullptr;
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
pFullscreenWindow = PFULLWINDOW;
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, PWORKSPACE->m_efFullscreenMode);
}
PWINDOW->updateSpecialRenderData();
// disallow tiled pinned
if (PWINDOW->m_bPinned && !PWINDOW->m_bIsFloating)
PWINDOW->m_bPinned = false;
if (requestedWorkspace != "") {
// process requested workspace
if (requestedWorkspace.contains(' ')) {
// check for silent
if (requestedWorkspace.contains("silent")) {
const CVarList WORKSPACEARGS = CVarList(requestedWorkspace, 0, ' ');
if (!WORKSPACEARGS[0].empty()) {
if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].starts_with("silent"))
workspaceSilent = true;
std::string requestedWorkspaceName;
const int REQUESTEDWORKSPACEID = getWorkspaceIDFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0), requestedWorkspaceName);
if (REQUESTEDWORKSPACEID != WORKSPACE_INVALID) {
auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID);
if (!pWorkspace)
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName);
PWINDOW->m_iWorkspaceID = pWorkspace->m_iID;
PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID;
if (g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->specialWorkspaceID && !pWorkspace->m_bIsSpecialWorkspace)
workspaceSilent = true;
shouldFocus = false;
requestedWorkspace = requestedWorkspace.substr(0, requestedWorkspace.find_first_of(' '));
if (!workspaceSilent) {
if (pWorkspace->m_bIsSpecialWorkspace)
g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID)->setSpecialWorkspace(pWorkspace);
else
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
PMONITOR = g_pCompositor->m_pLastMonitor;
}
if (!shouldFocus && requestedWorkspace == std::to_string(PMONITOR->activeWorkspace))
shouldFocus = true;
}
if (requestedWorkspace.find("special") == 0) {
workspaceSpecial = true;
workspaceSilent = true;
}
if (!workspaceSilent) {
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspace);
PWINDOW->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID;
PWINDOW->m_iWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
PMONITOR = g_pCompositor->m_pLastMonitor;
}
}
if (workspaceSilent) {
// get the workspace
auto PWORKSPACE = g_pCompositor->getWorkspaceByString(requestedWorkspace);
if (!PWORKSPACE) {
std::string workspaceName = "";
int workspaceID = 0;
if (requestedWorkspace.find("name:") == 0) {
workspaceName = requestedWorkspace.substr(5);
workspaceID = g_pCompositor->getNextAvailableNamedWorkspace();
} else if (workspaceSpecial) {
workspaceName = "";
workspaceID = getWorkspaceIDFromString(requestedWorkspace, workspaceName);
} else {
try {
workspaceID = std::stoi(requestedWorkspace);
} catch (...) {
workspaceID = -1;
Debug::log(ERR, "Invalid workspace requested in workspace silent rule!");
}
if (workspaceID < 1) {
workspaceID = -1; // means invalid
}
}
if (workspaceID != -1)
PWORKSPACE = g_pCompositor->createNewWorkspace(workspaceID, PWINDOW->m_iMonitorID, workspaceName);
}
if (PWORKSPACE) {
PWINDOW->m_iWorkspaceID = PWORKSPACE->m_iID;
PWINDOW->m_iMonitorID = PWORKSPACE->m_iMonitorID;
}
} else
workspaceSilent = false;
}
if (PWINDOW->m_bIsFloating) {
@@ -305,7 +295,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// size and move rules
for (auto& r : WINDOWRULES) {
if (r.szRule.find("size") == 0) {
if (r.szRule.starts_with("size")) {
try {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
@@ -320,14 +310,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) :
(!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
Debug::log(LOG, "Rule size, applying to window %lx", PWINDOW);
Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str()); }
} else if (r.szRule.find("minsize") == 0) {
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("minsize")) {
try {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
@@ -340,8 +330,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
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) {
} catch (...) { Debug::log(LOG, "Rule minsize failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("maxsize")) {
try {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
@@ -354,12 +344,17 @@ void Events::listener_mapWindow(void* owner, void* data) {
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) {
} catch (...) { Debug::log(LOG, "Rule maxsize failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("move")) {
try {
auto value = r.szRule.substr(r.szRule.find(' ') + 1);
const bool CURSOR = value.find("cursor") == 0;
const bool ONSCREEN = value.starts_with("onscreen");
if (ONSCREEN)
value = value.substr(value.find_first_of(' ') + 1);
const bool CURSOR = value.starts_with("cursor");
if (CURSOR)
value = value.substr(value.find_first_of(' ') + 1);
@@ -370,9 +365,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
int posX = 0;
int posY = 0;
if (POSXSTR.find("100%-") == 0) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto POSXRAW = POSXSTR.substr(5);
if (POSXSTR.starts_with("100%-")) {
const auto POSXRAW = POSXSTR.substr(5);
posX =
PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
@@ -390,9 +384,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
}
if (POSYSTR.find("100%-") == 0) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto POSYRAW = POSYSTR.substr(5);
if (POSYSTR.starts_with("100%-")) {
const auto POSYRAW = POSYSTR.substr(5);
posY =
PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
@@ -410,19 +403,29 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
}
Debug::log(LOG, "Rule move, applying to window %lx", PWINDOW);
if (ONSCREEN) {
int borderSize = PWINDOW->getRealBorderSize();
posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goalv().x - borderSize));
posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goalv().y - borderSize));
}
Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule move failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str()); }
} else if (r.szRule.find("center") == 0) {
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("center")) {
auto RESERVEDOFFSET = Vector2D();
const auto ARGS = CVarList(r.szRule, 2, ' ');
if (ARGS[1] == "1")
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
PWINDOW->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.f - PWINDOW->m_vRealSize.goalv() / 2.f + RESERVEDOFFSET;
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goalv() / 2.f + RESERVEDOFFSET;
}
}
@@ -430,7 +433,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// because the windows are animated on RealSize
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv();
g_pCompositor->moveWindowToTop(PWINDOW);
g_pCompositor->changeWindowZOrder(PWINDOW, true);
} else {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
@@ -451,6 +454,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
PWINDOW->m_bNoInitialFocus = true;
if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
if (*PNEWTAKESOVERFS == 0)
PWINDOW->m_bNoInitialFocus = true;
else if (*PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID);
else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
requestsMaximize = true;
else
requestsFullscreen = true;
}
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus &&
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
@@ -463,7 +476,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_fDimPercent.setValueAndWarp(0);
}
Debug::log(LOG, "Window got assigned a surfaceTreeNode %lx", PWINDOW->m_pSurfaceTree);
Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree);
if (!PWINDOW->m_bIsX11) {
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xdg->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XDG Window Late");
@@ -477,6 +490,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
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");
PWINDOW->hyprListener_ackConfigure.initCallback(&PWINDOW->m_uSurface.xdg->events.ack_configure, &Events::listener_ackConfigure, PWINDOW, "XDG Window Late");
} else {
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW,
"XWayland Window Late");
@@ -520,10 +534,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
}
if (pFullscreenWindow && workspaceSilent) {
g_pCompositor->setWindowFullscreen(pFullscreenWindow, true, PWORKSPACE->m_efFullscreenMode);
}
// recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus();
@@ -531,7 +541,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->updateToplevel();
if (!shouldFocus) {
if (workspaceSilent) {
if (g_pCompositor->windowValidMapped(PFOCUSEDWINDOWPREV)) {
g_pCompositor->focusWindow(PFOCUSEDWINDOWPREV);
PFOCUSEDWINDOWPREV->updateWindowDecos(); // need to for some reason i cba to find out why
@@ -601,6 +611,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(finalFound);
finalFound->setHidden(true);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
}
}
}
@@ -609,32 +621,47 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bFirstMap = false;
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 {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goalv(), PWINDOW->m_vRealSize.goalv());
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
g_pEventManager->postEvent(
SHyprIPCEvent{"openwindow", getFormat("%lx,%s,%s,%s", PWINDOW, workspaceID.c_str(), g_pXWaylandManager->getAppIDClass(PWINDOW).c_str(), PWINDOW->m_szTitle.c_str())});
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, g_pXWaylandManager->getAppIDClass(PWINDOW), PWINDOW->m_szTitle)});
EMIT_HOOK_EVENT("openWindow", PWINDOW);
// recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
// avoid this window being visible
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating)
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == g_pCompositor->m_pLastWindow)
g_pInputManager->simulateMouseMovement();
// fix some xwayland apps that don't behave nicely
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
}
void Events::listener_unmapWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
Debug::log(LOG, "Window %lx unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
Debug::log(LOG, "{:c} unmapped", PWINDOW);
if (!PWINDOW->m_pWLSurface.exists() || !PWINDOW->m_bIsMapped) {
Debug::log(WARN, "Window %lx unmapped without being mapped??", PWINDOW);
Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW);
PWINDOW->m_bFadingOut = false;
return;
}
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%lx", PWINDOW)});
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR) {
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
}
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW);
@@ -649,6 +676,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->hyprListener_requestMove.removeCallback();
PWINDOW->hyprListener_requestResize.removeCallback();
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
PWINDOW->hyprListener_ackConfigure.removeCallback();
} else {
Debug::log(LOG, "Unregistered late callbacks XWL");
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
@@ -662,13 +690,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (PWINDOW->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR) {
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
}
// Allow the renderer to catch the last frame.
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
@@ -706,21 +727,25 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (wasLastWindow) {
const auto PWINDOWCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW);
Debug::log(LOG, "On closed window, new focused candidate is %lx", PWINDOWCANDIDATE);
Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE);
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow) {
if (!PWINDOWCANDIDATE)
g_pInputManager->simulateMouseMovement();
else
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
} else {
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == PWINDOWCANDIDATE)
g_pInputManager->simulateMouseMovement();
// CWindow::onUnmap will remove this window's active status, but we can't really do it above.
if (PWINDOW == g_pCompositor->m_pLastWindow || !g_pCompositor->m_pLastWindow) {
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ","});
EMIT_HOOK_EVENT("activeWindow", (CWindow*)nullptr);
}
} else {
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
}
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window %lx", PWINDOW);
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window {}", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
PWINDOW->m_pSurfaceTree = nullptr;
@@ -751,12 +776,33 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->onUnmap();
}
void Events::listener_ackConfigure(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
const auto E = (wlr_xdg_surface_configure*)data;
// find last matching serial
const auto SERIAL = std::find_if(PWINDOW->m_vPendingSizeAcks.rbegin(), PWINDOW->m_vPendingSizeAcks.rend(), [&](const auto& e) { return e.first == E->serial; });
if (SERIAL == PWINDOW->m_vPendingSizeAcks.rend())
return;
PWINDOW->m_pPendingSizeAck = *SERIAL;
std::erase_if(PWINDOW->m_vPendingSizeAcks, [&](const auto& el) { return el.first == SERIAL->first; });
}
void Events::listener_commitWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11))
return;
if (PWINDOW->m_bIsX11)
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
else if (PWINDOW->m_pPendingSizeAck.has_value()) {
PWINDOW->m_vReportedSize = PWINDOW->m_pPendingSizeAck->second;
PWINDOW->m_pPendingSizeAck.reset();
}
PWINDOW->updateSurfaceOutputs();
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
@@ -787,10 +833,10 @@ void Events::listener_commitWindow(void* owner, void* data) {
void Events::listener_destroyWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
Debug::log(LOG, "Window %lx destroyed, queueing. (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
Debug::log(LOG, "{:c} destroyed, queueing.", PWINDOW);
if (PWINDOW->m_bIsX11)
Debug::log(LOG, "XWayland class raw: %s", PWINDOW->m_uSurface.xwayland->_class);
Debug::log(LOG, "XWayland class raw: {}", PWINDOW->m_uSurface.xwayland->_class ? PWINDOW->m_uSurface.xwayland->_class : "null");
if (PWINDOW == g_pCompositor->m_pLastWindow) {
g_pCompositor->m_pLastWindow = nullptr;
@@ -808,7 +854,7 @@ void Events::listener_destroyWindow(void* owner, void* data) {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
if (PWINDOW->m_pSurfaceTree) {
Debug::log(LOG, "Destroying Subsurface tree of %lx in destroyWindow", PWINDOW);
Debug::log(LOG, "Destroying Subsurface tree of {} in destroyWindow", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
PWINDOW->m_pSurfaceTree = nullptr;
}
@@ -816,8 +862,8 @@ void Events::listener_destroyWindow(void* owner, void* data) {
PWINDOW->m_bReadyToDelete = true;
if (!PWINDOW->m_bFadingOut) {
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
Debug::log(LOG, "Unmapped window %lx removed instantly", PWINDOW);
}
}
@@ -828,12 +874,12 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
return;
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", getFormat("%lx", PWINDOW)});
g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)PWINDOW)});
EMIT_HOOK_EVENT("windowTitle", PWINDOW);
if (PWINDOW == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle});
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", getFormat("%lx", PWINDOW)});
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)PWINDOW)});
EMIT_HOOK_EVENT("activeWindow", PWINDOW);
}
@@ -841,7 +887,7 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
PWINDOW->updateToplevel();
Debug::log(LOG, "Window %lx set title to %s", PWINDOW, PWINDOW->m_szTitle.c_str());
Debug::log(LOG, "Window {:x} set title to {}", PWINDOW, PWINDOW->m_szTitle);
}
void Events::listener_fullscreenWindow(void* owner, void* data) {
@@ -900,7 +946,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
PWINDOW->updateToplevel();
Debug::log(LOG, "Window %lx fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen);
Debug::log(LOG, "{} fullscreen to {}", PWINDOW, PWINDOW->m_bIsFullscreen);
}
void Events::listener_activateXDG(wl_listener* listener, void* data) {
@@ -908,7 +954,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
Debug::log(LOG, "Activate request for surface at %lx", E->surface);
Debug::log(LOG, "Activate request for surface at {:x}", (uintptr_t)E->surface);
if (!wlr_xdg_surface_try_from_wlr_surface(E->surface))
return;
@@ -918,25 +964,19 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow)
return;
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", getFormat("%lx", PWINDOW)});
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
EMIT_HOOK_EVENT("urgent", PWINDOW);
PWINDOW->m_bIsUrgent = true;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
if (PWORKSPACE->m_pWlrHandle) {
wlr_ext_workspace_handle_v1_set_urgent(PWORKSPACE->m_pWlrHandle, 1);
}
if (!*PFOCUSONACTIVATE)
return;
if (PWINDOW->m_bIsFloating)
g_pCompositor->moveWindowToTop(PWINDOW);
g_pCompositor->changeWindowZOrder(PWINDOW, true);
g_pCompositor->focusWindow(PWINDOW);
Vector2D middle = PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f;
g_pCompositor->warpCursorTo(middle);
g_pCompositor->warpCursorTo(PWINDOW->middle());
}
void Events::listener_activateX11(void* owner, void* data) {
@@ -944,11 +984,11 @@ void Events::listener_activateX11(void* owner, void* data) {
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
Debug::log(LOG, "X11 Activate request for window %lx", PWINDOW);
Debug::log(LOG, "X11 Activate request for window {}", PWINDOW);
if (PWINDOW->m_iX11Type == 2) {
Debug::log(LOG, "Unmanaged X11 %lx requests activate", PWINDOW);
Debug::log(LOG, "Unmanaged X11 {} requests activate", PWINDOW);
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID())
return;
@@ -960,18 +1000,17 @@ void Events::listener_activateX11(void* owner, void* data) {
if (PWINDOW == g_pCompositor->m_pLastWindow)
return;
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", getFormat("%lx", PWINDOW)});
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
EMIT_HOOK_EVENT("urgent", PWINDOW);
if (!*PFOCUSONACTIVATE)
return;
if (PWINDOW->m_bIsFloating)
g_pCompositor->moveWindowToTop(PWINDOW);
g_pCompositor->changeWindowZOrder(PWINDOW, true);
g_pCompositor->focusWindow(PWINDOW);
Vector2D middle = PWINDOW->m_vRealPosition.goalv() + PWINDOW->m_vRealSize.goalv() / 2.f;
g_pCompositor->warpCursorTo(middle);
g_pCompositor->warpCursorTo(PWINDOW->middle());
}
void Events::listener_configureX11(void* owner, void* data) {
@@ -981,6 +1020,7 @@ void Events::listener_configureX11(void* owner, void* data) {
if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bMappedX11) {
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
PWINDOW->m_vReportedSize = {E->width, E->height};
return;
}
@@ -1005,8 +1045,11 @@ void Events::listener_configureX11(void* owner, void* data) {
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
}
}
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
@@ -1016,7 +1059,7 @@ void Events::listener_configureX11(void* owner, void* data) {
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
g_pCompositor->moveWindowToTop(PWINDOW);
g_pCompositor->changeWindowZOrder(PWINDOW, true);
PWINDOW->m_bCreatedOverFullscreen = true;
@@ -1026,6 +1069,8 @@ void Events::listener_configureX11(void* owner, void* data) {
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->updateWindowDecos();
PWINDOW->m_vReportedSize = {E->width, E->height};
}
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
@@ -1054,7 +1099,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
if (abs(std::floor(POS.x) - LOGICALPOS.x) > 2 || abs(std::floor(POS.y) - LOGICALPOS.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 %lx requests geometry update to %i %i %i %i", PWINDOW, (int)LOGICALPOS.x, (int)LOGICALPOS.y, (int)PWINDOW->m_uSurface.xwayland->width,
Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {} {}", PWINDOW, LOGICALPOS, (int)PWINDOW->m_uSurface.xwayland->width,
(int)PWINDOW->m_uSurface.xwayland->height);
g_pHyprRenderer->damageWindow(PWINDOW);
@@ -1064,8 +1109,11 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height));
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
}
}
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
@@ -1073,7 +1121,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
g_pCompositor->moveWindowToTop(PWINDOW);
g_pCompositor->changeWindowZOrder(PWINDOW, true);
PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW);
}
@@ -1102,9 +1150,9 @@ void Events::listener_dissociateX11(void* owner, void* data) {
void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
const auto XWSURFACE = (wlr_xwayland_surface*)data;
Debug::log(LOG, "New XWayland Surface created (class %s).", XWSURFACE->_class);
Debug::log(LOG, "New XWayland Surface created (class {}).", XWSURFACE->_class ? XWSURFACE->_class : "null");
if (XWSURFACE->parent)
Debug::log(LOG, "Window parent data: %s at %lx", XWSURFACE->parent->_class, XWSURFACE->parent);
Debug::log(LOG, "Window parent data: {} at {:x}", XWSURFACE->parent->_class ? XWSURFACE->parent->_class : "null", (uintptr_t)XWSURFACE->parent);
const auto PNEWWINDOW = (CWindow*)g_pCompositor->m_vWindows.emplace_back(std::make_unique<CWindow>()).get();
@@ -1121,14 +1169,12 @@ void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW, "XWayland Window");
}
void Events::listener_newXDGSurface(wl_listener* listener, void* data) {
void Events::listener_newXDGToplevel(wl_listener* listener, void* data) {
// A window got opened
const auto XDGSURFACE = (wlr_xdg_surface*)data;
const auto XDGTOPLEVEL = (wlr_xdg_toplevel*)data;
const auto XDGSURFACE = XDGTOPLEVEL->base;
if (XDGSURFACE->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
return;
Debug::log(LOG, "New XDG Surface created. (class: %s)", XDGSURFACE->toplevel->app_id);
Debug::log(LOG, "New XDG Toplevel created. (class: {})", XDGSURFACE->toplevel->app_id ? XDGSURFACE->toplevel->app_id : "null");
const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(std::make_unique<CWindow>()).get();
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
@@ -1148,7 +1194,7 @@ void Events::listener_requestMaximize(void* owner, void* data) {
if (PWINDOW->m_bNoMaximizeRequest)
return;
Debug::log(LOG, "Maximize request for %lx", PWINDOW);
Debug::log(LOG, "Maximize request for {}", PWINDOW);
if (!PWINDOW->m_bIsX11) {
const auto EV = (wlr_foreign_toplevel_handle_v1_maximized_event*)data;
@@ -1167,7 +1213,7 @@ void Events::listener_requestMaximize(void* owner, void* data) {
void Events::listener_requestMinimize(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner;
Debug::log(LOG, "Minimize request for %lx", PWINDOW);
Debug::log(LOG, "Minimize request for {}", PWINDOW);
if (PWINDOW->m_bIsX11) {
if (!PWINDOW->m_bMappedX11 || PWINDOW->m_iX11Type != 1)
@@ -1175,13 +1221,13 @@ void Events::listener_requestMinimize(void* owner, void* data) {
const auto E = (wlr_xwayland_minimize_event*)data;
g_pEventManager->postEvent({"minimize", getFormat("%lx,%i", PWINDOW, (int)E->minimize)});
g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW, (int)E->minimize)});
EMIT_HOOK_EVENT("minimize", (std::vector<void*>{PWINDOW, (void*)E->minimize}));
wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow != PWINDOW); // fucking DXVK
} else {
const auto E = (wlr_foreign_toplevel_handle_v1_minimized_event*)data;
g_pEventManager->postEvent({"minimize", getFormat("%lx,%i", PWINDOW, E ? (int)E->minimized : 1)});
g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW, E ? (int)E->minimized : 1)});
EMIT_HOOK_EVENT("minimize", (std::vector<void*>{PWINDOW, (void*)(E ? (uint64_t)E->minimized : 1)}));
}
}

View File

@@ -41,8 +41,8 @@ void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, SAnimationPro
default: ASSERT(false); break;
}
} catch (std::exception& e) {
Debug::log(ERR, "CAnimatedVariable create error: %s", e.what());
RASSERT(false, "CAnimatedVariable create error: %s", e.what());
Debug::log(ERR, "CAnimatedVariable create error: {}", e.what());
RASSERT(false, "CAnimatedVariable create error: {}", e.what());
}
}
@@ -51,6 +51,8 @@ CAnimatedVariable::~CAnimatedVariable() {
}
void CAnimatedVariable::unregister() {
if (!g_pAnimationManager)
return;
std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; });
m_bIsRegistered = false;
disconnectFromActive();

View File

@@ -6,15 +6,18 @@
#include "Vector2D.hpp"
#include "Color.hpp"
#include "../macros.hpp"
#include "../debug/Log.hpp"
enum ANIMATEDVARTYPE {
enum ANIMATEDVARTYPE
{
AVARTYPE_INVALID = -1,
AVARTYPE_FLOAT,
AVARTYPE_VECTOR,
AVARTYPE_COLOR
};
enum AVARDAMAGEPOLICY {
enum AVARDAMAGEPOLICY
{
AVARDAMAGE_NONE = -1,
AVARDAMAGE_ENTIRE = 0,
AVARDAMAGE_BORDER,
@@ -34,10 +37,10 @@ class CAnimatedVariable {
void create(ANIMATEDVARTYPE, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
void create(ANIMATEDVARTYPE, std::any val, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
CAnimatedVariable(const CAnimatedVariable&) = delete;
CAnimatedVariable(CAnimatedVariable&&) = delete;
CAnimatedVariable(const CAnimatedVariable&) = delete;
CAnimatedVariable(CAnimatedVariable&&) = delete;
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
~CAnimatedVariable();
@@ -75,6 +78,9 @@ class CAnimatedVariable {
}
CAnimatedVariable& operator=(const Vector2D& v) {
if (v == m_vGoal)
return *this;
m_vGoal = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
@@ -85,6 +91,9 @@ class CAnimatedVariable {
}
CAnimatedVariable& operator=(const float& v) {
if (v == m_fGoal)
return *this;
m_fGoal = v;
animationBegin = std::chrono::system_clock::now();
m_fBegun = m_fValue;
@@ -95,6 +104,9 @@ class CAnimatedVariable {
}
CAnimatedVariable& operator=(const CColor& v) {
if (v == m_cGoal)
return *this;
m_cGoal = v;
animationBegin = std::chrono::system_clock::now();
m_cBegun = m_cValue;
@@ -106,6 +118,9 @@ class CAnimatedVariable {
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const Vector2D& v) {
if (v == m_vValue)
return;
m_vValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
@@ -115,6 +130,9 @@ class CAnimatedVariable {
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const float& v) {
if (v == m_fValue)
return;
m_fValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
@@ -124,6 +142,9 @@ class CAnimatedVariable {
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const CColor& v) {
if (v == m_cValue)
return;
m_cValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;

View File

@@ -18,7 +18,7 @@ void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
m_dPoints.emplace_back(Vector2D(1, 1));
RASSERT(m_dPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: %i)", m_dPoints.size());
RASSERT(m_dPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_dPoints.size());
// bake BAKEDPOINTS points for faster lookups
// T -> X ( / BAKEDPOINTS )
@@ -34,8 +34,8 @@ void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
getYForPoint(i);
const auto ELAPSEDCALCAVG = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f;
Debug::log(LOG, "Created a bezier curve, baked %i points, mem usage: %.2fkB, time to bake: %.2fµs. Estimated average calc time: %.2fµs.", BAKEDPOINTS, POINTSSIZE, ELAPSEDUS,
ELAPSEDCALCAVG);
Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE,
ELAPSEDUS, ELAPSEDCALCAVG);
}
float CBezierCurve::getYForT(float t) {
@@ -48,27 +48,25 @@ float CBezierCurve::getXForT(float t) {
// Todo: this probably can be done better and faster
float CBezierCurve::getYForPoint(float x) {
if (x >= 1.0)
return 1.0;
if (x >= 1.f)
return 1.f;
// binary search for the range UPDOWN X
int upperT = BAKEDPOINTS - 1;
int lowerT = 0;
int mid = upperT / 2;
int index = 0;
bool below = true;
for (int step = (BAKEDPOINTS + 1) / 2; step > 0; step /= 2) {
if (below)
index += step;
else
index -= step;
while (std::abs(upperT - lowerT) > 1) {
if (m_aPointsBaked[mid].x > x) {
upperT = mid;
} else {
lowerT = mid;
}
mid = (upperT + lowerT) / 2;
below = m_aPointsBaked[index].x < x;
}
int lowerIndex = index - (!below || index == BAKEDPOINTS - 1);
// in the name of performance i shall make a hack
const auto LOWERPOINT = &m_aPointsBaked[std::clamp(lowerT, 0, BAKEDPOINTS - 1)];
const auto UPPERPOINT = &m_aPointsBaked[std::clamp(upperT, 0, BAKEDPOINTS - 1)];
const auto LOWERPOINT = &m_aPointsBaked[lowerIndex];
const auto UPPERPOINT = &m_aPointsBaked[lowerIndex + 1];
const auto PERCINDELTA = (x - LOWERPOINT->x) / (UPPERPOINT->x - LOWERPOINT->x);
@@ -76,4 +74,4 @@ float CBezierCurve::getYForPoint(float x) {
return 0.f;
return LOWERPOINT->y + (UPPERPOINT->y - LOWERPOINT->y) * PERCINDELTA;
}
}

View File

@@ -10,7 +10,6 @@ constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS;
// an implementation of a cubic bezier curve
// might do better later
// TODO: n-point curves
class CBezierCurve {
public:
// sets up the bezier curve.
@@ -26,4 +25,4 @@ class CBezierCurve {
std::deque<Vector2D> m_dPoints;
std::array<Vector2D, BAKEDPOINTS> m_aPointsBaked;
};
};

129
src/helpers/Box.cpp Normal file
View File

@@ -0,0 +1,129 @@
#include "Box.hpp"
wlr_box CBox::wlr() {
CBox rounded = roundInternal();
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
return m_bWlrBox;
}
wlr_box* CBox::pWlr() {
CBox rounded = roundInternal();
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
return &m_bWlrBox;
}
CBox& CBox::scale(double scale) {
x *= scale;
y *= scale;
w *= scale;
h *= scale;
return *this;
}
CBox& CBox::scale(const Vector2D& scale) {
x *= scale.x;
y *= scale.y;
w *= scale.x;
h *= scale.y;
return *this;
}
CBox& CBox::translate(const Vector2D& vec) {
x += vec.x;
y += vec.y;
return *this;
}
Vector2D CBox::middle() const {
return Vector2D{x + w / 2.0, y + h / 2.0};
}
bool CBox::containsPoint(const Vector2D& vec) const {
return VECINRECT(vec, x, y, x + w, y + h);
}
bool CBox::empty() const {
return w == 0 || h == 0;
}
CBox& CBox::applyFromWlr() {
x = m_bWlrBox.x;
y = m_bWlrBox.y;
w = m_bWlrBox.width;
h = m_bWlrBox.height;
return *this;
}
CBox& CBox::round() {
float newW = x + w - std::round(x);
float newH = y + h - std::round(y);
x = std::round(x);
y = std::round(y);
w = std::round(newW);
h = std::round(newH);
return *this;
}
CBox& CBox::transform(const wl_output_transform t, double w, double h) {
wlr_box_transform(&m_bWlrBox, pWlr(), t, w, h);
applyFromWlr();
return *this;
}
CBox& CBox::addExtents(const SWindowDecorationExtents& e) {
x -= e.topLeft.x;
y -= e.topLeft.y;
w += e.topLeft.x + e.bottomRight.x;
h += e.topLeft.y + e.bottomRight.y;
return *this;
}
CBox& CBox::scaleFromCenter(double scale) {
double oldW = w, oldH = h;
w *= scale;
h *= scale;
x -= (w - oldW) / 2.0;
y -= (h - oldH) / 2.0;
return *this;
}
CBox& CBox::expand(const double& value) {
x -= value;
y -= value;
w += value * 2.0;
h += value * 2.0;
return *this;
}
CBox CBox::roundInternal() {
float newW = x + w - std::floor(x);
float newH = y + h - std::floor(y);
return CBox{std::floor(x), std::floor(y), std::floor(newW), std::floor(newH)};
}
CBox CBox::copy() const {
return CBox{*this};
}
Vector2D CBox::pos() const {
return {x, y};
}
Vector2D CBox::size() const {
return {w, h};
}
SWindowDecorationExtents CBox::extentsFrom(const CBox& small) {
return {{small.x - x, small.y - y}, {w - small.w - (small.x - x), h - small.h - (small.y - y)}};
}

85
src/helpers/Box.hpp Normal file
View File

@@ -0,0 +1,85 @@
#pragma once
#include "Vector2D.hpp"
#include "../SharedDefs.hpp"
#include "../includes.hpp"
class CBox {
public:
CBox(double x_, double y_, double w_, double h_) {
x = x_;
y = y_;
w = w_;
h = h_;
}
CBox() {
w = 0;
h = 0;
}
CBox(const wlr_box& box) {
x = box.x;
y = box.y;
w = box.width;
h = box.height;
}
CBox(const double d) {
x = d;
y = d;
w = d;
h = d;
}
CBox(const Vector2D& pos, const Vector2D& size) {
x = pos.x;
y = pos.y;
w = size.x;
h = size.y;
}
wlr_box wlr();
wlr_box* pWlr();
CBox& applyFromWlr();
CBox& scale(double scale);
CBox& scaleFromCenter(double scale);
CBox& scale(const Vector2D& scale);
CBox& translate(const Vector2D& vec);
CBox& round();
CBox& transform(const wl_output_transform t, double w, double h);
CBox& addExtents(const SWindowDecorationExtents& e);
CBox& expand(const double& value);
CBox copy() const;
SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box
Vector2D middle() const;
Vector2D pos() const;
Vector2D size() const;
bool containsPoint(const Vector2D& vec) const;
bool empty() const;
double x = 0, y = 0;
union {
double w;
double width;
};
union {
double h;
double height;
};
//
bool operator==(const CBox& rhs) const {
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
}
private:
CBox roundInternal();
wlr_box m_bWlrBox;
};

View File

@@ -5,7 +5,7 @@
class CColor {
public:
CColor();
CColor(float, float, float, float);
CColor(float r, float g, float b, float a);
CColor(uint64_t);
float r = 0, g = 0, b = 0, a = 1.f;
@@ -27,4 +27,8 @@ class CColor {
bool operator==(const CColor& c2) const {
return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
}
CColor stripA() const {
return {r, g, b, 1};
}
};

View File

@@ -2,11 +2,14 @@
#include "../defines.hpp"
#include <algorithm>
#include "../Compositor.hpp"
#include <optional>
#include <set>
#include <sys/utsname.h>
#include <iomanip>
#include <sstream>
#ifdef HAS_EXECINFO
#include <execinfo.h>
#endif
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sysctl.h>
@@ -126,20 +129,22 @@ 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 + currentPath.empty(), parentDir);
} else {
value.replace(0, 1 + currentPath.empty(), currentDir);
}
}
if (value[0] == '~') {
static const char* const ENVHOME = getenv("HOME");
value.replace(0, 1, std::string(ENVHOME));
} else if (value[0] != '/') {
auto currentDir = currentPath.substr(0, currentPath.find_last_of('/'));
if (value[0] == '.') {
if (value[1] == '.' && value[2] == '/') {
auto parentDir = currentDir.substr(0, currentDir.find_last_of('/'));
value.replace(0, 2 + currentPath.empty(), parentDir);
} else if (value[1] == '/')
value.replace(0, 1 + currentPath.empty(), currentDir);
else
value = currentDir + '/' + value;
} else
value = currentDir + '/' + value;
}
return value;
@@ -151,27 +156,13 @@ void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, const
wl_signal_add(pSignal, pListener);
Debug::log(LOG, "Registered signal for owner %lx: %lx -> %lx (owner: %s)", pOwner, pSignal, pListener, ownerString.c_str());
Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString);
}
void handleNoop(struct wl_listener* listener, void* data) {
// Do nothing
}
std::string getFormat(const char* fmt, ...) {
char* outputStr = nullptr;
va_list args;
va_start(args, fmt);
vasprintf(&outputStr, fmt, args);
va_end(args);
std::string output = std::string(outputStr);
free(outputStr);
return output;
}
std::string escapeJSONStrings(const std::string& str) {
std::ostringstream oss;
for (auto& c : str) {
@@ -194,13 +185,6 @@ std::string escapeJSONStrings(const std::string& str) {
return oss.str();
}
void scaleBox(wlr_box* box, float scale) {
box->width = std::round(box->width * scale);
box->height = std::round(box->height * scale);
box->x = std::round(box->x * scale);
box->y = std::round(box->y * scale);
}
std::string removeBeginEndSpacesTabs(std::string str) {
if (str.empty())
return str;
@@ -220,12 +204,12 @@ std::string removeBeginEndSpacesTabs(std::string str) {
return str;
}
float getPlusMinusKeywordResult(std::string source, float relative) {
std::optional<float> getPlusMinusKeywordResult(std::string source, float relative) {
try {
return relative + stof(source);
} catch (...) {
Debug::log(ERR, "Invalid arg \"%s\" in getPlusMinusKeywordResult!", source.c_str());
return INT_MAX;
Debug::log(ERR, "Invalid arg \"{}\" in getPlusMinusKeywordResult!", source);
return {};
}
}
@@ -258,9 +242,13 @@ bool isDirection(const std::string& arg) {
return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b";
}
bool isDirection(const char& arg) {
return arg == 'l' || arg == 'r' || arg == 'u' || arg == 'd' || arg == 't' || arg == 'b';
}
int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int result = INT_MAX;
if (in.find("special") == 0) {
int result = WORKSPACE_INVALID;
if (in.starts_with("special")) {
outName = "special";
if (in.length() > 8) {
@@ -274,7 +262,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
}
return SPECIAL_WORKSPACE_START;
} else if (in.find("name:") == 0) {
} else if (in.starts_with("name:")) {
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
if (!WORKSPACE) {
@@ -283,26 +271,26 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
result = WORKSPACE->m_iID;
}
outName = WORKSPACENAME;
} else if (in.find("empty") == 0) {
} else if (in.starts_with("empty")) {
int id = 0;
while (++id < INT_MAX) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0))
return id;
}
} else if (in.find("prev") == 0) {
} else if (in.starts_with("prev")) {
if (!g_pCompositor->m_pLastMonitor)
return INT_MAX;
return WORKSPACE_INVALID;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
if (!PWORKSPACE)
return INT_MAX;
return WORKSPACE_INVALID;
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.iID);
if (!PLASTWORKSPACE)
return INT_MAX;
return WORKSPACE_INVALID;
outName = PLASTWORKSPACE->m_szName;
return PLASTWORKSPACE->m_iID;
@@ -310,10 +298,15 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
if (in[0] == 'r' && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
if (!g_pCompositor->m_pLastMonitor) {
Debug::log(ERR, "Relative monitor workspace on monitor null!");
result = INT_MAX;
return result;
return WORKSPACE_INVALID;
}
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in.substr(1), 0);
if (!PLUSMINUSRESULT.has_value())
return WORKSPACE_INVALID;
result = (int)PLUSMINUSRESULT.value();
int remains = (int)result;
@@ -401,12 +394,12 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int beginID = finalWSID;
int curID = finalWSID;
while (--curID > 0 && remainingWSes > 0) {
if (invalidWSes.find(curID) == invalidWSes.end()) {
if (!invalidWSes.contains(curID)) {
remainingWSes--;
}
finalWSID = curID;
}
if (finalWSID <= 0 || invalidWSes.find(finalWSID) != invalidWSes.end()) {
if (finalWSID <= 0 || invalidWSes.contains(finalWSID)) {
if (namedWSes.size()) {
// Go to the named workspaces
// Need remainingWSes more
@@ -426,7 +419,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
if (walkDir == '+') {
int curID = finalWSID;
while (++curID < INT32_MAX && remainingWSes > 0) {
if (invalidWSes.find(curID) == invalidWSes.end()) {
if (!invalidWSes.contains(curID)) {
remainingWSes--;
}
finalWSID = curID;
@@ -445,12 +438,16 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
if (!g_pCompositor->m_pLastMonitor) {
Debug::log(ERR, "Relative monitor workspace on monitor null!");
result = INT_MAX;
return result;
return WORKSPACE_INVALID;
}
// monitor relative
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in.substr(1), 0);
if (!PLUSMINUSRESULT.has_value())
return WORKSPACE_INVALID;
result = (int)PLUSMINUSRESULT.value();
// result now has +/- what we should move on mon
int remains = (int)result;
@@ -491,11 +488,15 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName;
} else {
if (in[0] == '+' || in[0] == '-') {
if (g_pCompositor->m_pLastMonitor)
result = std::max((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1);
else {
if (g_pCompositor->m_pLastMonitor) {
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace);
if (!PLUSMINUSRESULT.has_value())
return WORKSPACE_INVALID;
result = std::max((int)PLUSMINUSRESULT.value(), 1);
} else {
Debug::log(ERR, "Relative workspace on no mon!");
result = INT_MAX;
return WORKSPACE_INVALID;
}
} else if (isNumber(in))
result = std::max(std::stoi(in), 1);
@@ -513,6 +514,43 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
return result;
}
std::optional<std::string> cleanCmdForWorkspace(const std::string& inWorkspaceName, std::string dirtyCmd) {
std::string cmd = removeBeginEndSpacesTabs(dirtyCmd);
if (!cmd.empty()) {
std::string rules;
const std::string workspaceRule = "workspace " + inWorkspaceName;
if (cmd[0] == '[') {
const int closingBracketIdx = cmd.find_last_of(']');
auto tmpRules = cmd.substr(1, closingBracketIdx - 1);
cmd = cmd.substr(closingBracketIdx + 1);
auto rulesList = CVarList(tmpRules, 0, ';');
bool hadWorkspaceRule = false;
rulesList.map([&](std::string& rule) {
if (rule.find("workspace") == 0) {
rule = workspaceRule;
hadWorkspaceRule = true;
}
});
if (!hadWorkspaceRule)
rulesList.append(workspaceRule);
rules = "[" + rulesList.join(";") + "]";
} else {
rules = "[" + workspaceRule + "]";
}
return std::optional<std::string>(rules + " " + cmd);
}
return std::nullopt;
}
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) {
const float DX = std::max({0.0, p1.x - vec.x, vec.x - p2.x});
const float DY = std::max({0.0, p1.y - vec.y, vec.y - p2.y});
@@ -539,10 +577,10 @@ void logSystemInfo() {
uname(&unameInfo);
Debug::log(LOG, "System name: %s", unameInfo.sysname);
Debug::log(LOG, "Node name: %s", unameInfo.nodename);
Debug::log(LOG, "Release: %s", unameInfo.release);
Debug::log(LOG, "Version: %s", unameInfo.version);
Debug::log(LOG, "System name: {}", unameInfo.sysname);
Debug::log(LOG, "Node name: {}", unameInfo.nodename);
Debug::log(LOG, "Release: {}", unameInfo.release);
Debug::log(LOG, "Version: {}", unameInfo.version);
Debug::log(NONE, "\n");
@@ -551,7 +589,7 @@ void logSystemInfo() {
#else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif
Debug::log(LOG, "GPU information:\n%s\n", GPUINFO.c_str());
Debug::log(LOG, "GPU information:\n{}\n", GPUINFO);
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");
@@ -560,7 +598,7 @@ void logSystemInfo() {
// log etc
Debug::log(LOG, "os-release:");
Debug::log(NONE, "%s", execAndGet("cat /etc/os-release").c_str());
Debug::log(NONE, "{}", execAndGet("cat /etc/os-release"));
}
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
@@ -638,15 +676,15 @@ int64_t getPPIDof(int64_t pid) {
}
int64_t configStringToInt(const std::string& VALUE) {
if (VALUE.find("0x") == 0) {
if (VALUE.starts_with("0x")) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
return stol(VALUEWITHOUTHEX, nullptr, 16);
} else if (VALUE.find("rgba(") == 0 && VALUE.find(')') == VALUE.length() - 1) {
} else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) {
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
Debug::log(WARN, "invalid length %i for rgba", VALUEWITHOUTFUNC.length());
Debug::log(WARN, "invalid length {} for rgba", VALUEWITHOUTFUNC.length());
throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)");
}
@@ -654,22 +692,26 @@ int64_t configStringToInt(const std::string& VALUE) {
// now we need to RGBA -> ARGB. The config holds ARGB only.
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
} else if (VALUE.find("rgb(") == 0 && VALUE.find(')') == VALUE.length() - 1) {
} else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) {
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
Debug::log(WARN, "invalid length %i for rgb", VALUEWITHOUTFUNC.length());
Debug::log(WARN, "invalid length {} for rgb", VALUEWITHOUTFUNC.length());
throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)");
}
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
return RGB + 0xFF000000; // 0xFF for opaque
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
} else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) {
return 1;
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
return 0;
}
if (VALUE.empty() || !isNumber(VALUE))
return 0;
return std::stoll(VALUE);
}
@@ -701,9 +743,10 @@ std::string replaceInString(std::string subject, const std::string& search, cons
std::vector<SCallstackFrameInfo> getBacktrace() {
std::vector<SCallstackFrameInfo> callstack;
void* bt[1024];
size_t btSize;
char** btSymbols;
#ifdef HAS_EXECINFO
void* bt[1024];
size_t btSize;
char** btSymbols;
btSize = backtrace(bt, 1024);
btSymbols = backtrace_symbols(bt, btSize);
@@ -711,11 +754,41 @@ std::vector<SCallstackFrameInfo> getBacktrace() {
for (size_t i = 0; i < btSize; ++i) {
callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}});
}
#else
callstack.emplace_back(SCallstackFrameInfo{nullptr, "configuration does not support execinfo.h"});
#endif
return callstack;
}
void throwError(const std::string& err) {
Debug::log(CRIT, "Critical error thrown: %s", err.c_str());
Debug::log(CRIT, "Critical error thrown: {}", err);
throw std::runtime_error(err);
}
uint32_t drmFormatToGL(uint32_t drm) {
switch (drm) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
#ifdef GLES2
return GL_RGB10_A2_EXT;
#else
return GL_RGB10_A2;
#endif
default: return GL_RGBA;
}
UNREACHABLE();
return GL_RGBA;
}
uint32_t glFormatToType(uint32_t gl) {
return gl != GL_RGBA ?
#ifdef GLES2
GL_UNSIGNED_INT_2_10_10_10_REV_EXT :
#else
GL_UNSIGNED_INT_2_10_10_10_REV :
#endif
GL_UNSIGNED_BYTE;
}

View File

@@ -1,10 +1,12 @@
#pragma once
#include <optional>
#include <string>
#include <wayland-server.h>
#include <wlr/util/box.h>
#include "Vector2D.hpp"
#include <vector>
#include <format>
struct SCallstackFrameInfo {
void* adr = nullptr;
@@ -13,21 +15,31 @@ struct SCallstackFrameInfo {
std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
std::string getFormat(const char* fmt, ...); // Basically Debug::log to a string
std::string escapeJSONStrings(const std::string& str);
void scaleBox(wlr_box*, float);
std::string removeBeginEndSpacesTabs(std::string);
bool isNumber(const std::string&, bool allowfloat = false);
bool isDirection(const std::string&);
bool isDirection(const char&);
int getWorkspaceIDFromString(const std::string&, std::string&);
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
void logSystemInfo();
std::string execAndGet(const char*);
int64_t getPPIDof(int64_t pid);
int64_t configStringToInt(const std::string&);
float getPlusMinusKeywordResult(std::string in, float relative);
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
double normalizeAngleRad(double ang);
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err);
void throwError(const std::string& err);
uint32_t drmFormatToGL(uint32_t drm);
uint32_t glFormatToType(uint32_t gl);
template <typename... Args>
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {
// no need for try {} catch {} because std::format_string<Args...> ensures that vformat never throw std::format_error
// because any suck format specifier will cause a compilation error
// this is actually what std::format in stdlib does
return std::vformat(fmt.get(), std::make_format_args(args...));
}

View File

@@ -40,6 +40,8 @@ void CMonitor::onConnect(bool noRule) {
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this);
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
if (m_bEnabled) {
wlr_output_enable(output, 1);
wlr_output_commit(output);
@@ -48,6 +50,10 @@ void CMonitor::onConnect(bool noRule) {
szName = output->name;
szDescription = output->description ? output->description : "";
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
szDescription.erase(std::remove(szDescription.begin(), szDescription.end(), ','), szDescription.end());
if (!wlr_backend_is_drm(output->backend))
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
@@ -79,15 +85,12 @@ void CMonitor::onConnect(bool noRule) {
if (PREFSTATE)
wlr_output_set_mode(output, PREFSTATE);
else
Debug::log(WARN, "No mode found for disabled output %s", output->name);
Debug::log(WARN, "No mode found for disabled output {}", output->name);
wlr_output_enable(output, 0);
if (!wlr_output_commit(output)) {
Debug::log(ERR, "Couldn't commit disabled state on output %s", output->name);
}
Events::listener_change(nullptr, nullptr);
if (!wlr_output_commit(output))
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
m_bEnabled = false;
@@ -110,47 +113,36 @@ void CMonitor::onConnect(bool noRule) {
m_bRenderingInitPassed = true;
}
if (!m_pThisWrap) {
std::shared_ptr<CMonitor>* thisWrapper = nullptr;
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
m_pThisWrap = &m;
break;
}
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
thisWrapper = &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);
}
RASSERT(thisWrapper->get(), "CMonitor::onConnect: Had no wrapper???");
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(*thisWrapper);
m_bEnabled = true;
// create it in the arr
vecPosition = monitorRule.offset;
vecSize = monitorRule.resolution;
refreshRate = monitorRule.refreshRate;
wlr_output_enable(output, 1);
// set mode, also applies
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
wlr_output_commit(output);
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %lx", output->name, (int)vecPosition.x, (int)vecPosition.y, (int)vecPixelSize.x,
(int)vecPixelSize.y, output);
// add a WLR workspace group
if (!pWLRWorkspaceGroupHandle) {
pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
}
wlr_ext_workspace_group_handle_v1_output_enter(pWLRWorkspaceGroupHandle, output);
Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output);
setupDefaultWS(monitorRule);
@@ -166,8 +158,6 @@ void CMonitor::onConnect(bool noRule) {
if (scale < 0.1)
scale = getDefaultScale();
m_pThisWrap = nullptr;
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
//
@@ -198,9 +188,11 @@ void CMonitor::onConnect(bool noRule) {
g_pCompositor->setActiveMonitor(this);
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
g_pCompositor->scheduleFrameForMonitor(this);
}
void CMonitor::onDisconnect() {
void CMonitor::onDisconnect(bool destroy) {
if (renderTimer) {
wl_event_source_remove(renderTimer);
@@ -210,7 +202,7 @@ void CMonitor::onDisconnect() {
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
return;
Debug::log(LOG, "onDisconnect called for %s", output->name);
Debug::log(LOG, "onDisconnect called for {}", output->name);
// Cleanup everything. Move windows back, snap cursor, shit.
CMonitor* BACKUPMON = nullptr;
@@ -235,9 +227,6 @@ void CMonitor::onDisconnect() {
g_pConfigManager->m_bWantsMonitorReload = true;
}
m_bEnabled = false;
m_bRenderingInitPassed = false;
hyprListener_monitorFrame.removeCallback();
hyprListener_monitorDamage.removeCallback();
hyprListener_monitorNeedsFrame.removeCallback();
@@ -252,52 +241,52 @@ void CMonitor::onDisconnect() {
m_aLayerSurfaceLayers[i].clear();
}
Debug::log(LOG, "Removed monitor %s!", szName.c_str());
Debug::log(LOG, "Removed monitor {}!", szName);
g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName});
EMIT_HOOK_EVENT("monitorRemoved", this);
if (!BACKUPMON) {
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
hyprListener_monitorStateRequest.removeCallback();
hyprListener_monitorDestroy.removeCallback();
g_pCompositor->m_bUnsafeState = true;
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
return;
g_pCompositor->enterUnsafeState();
}
// snap cursor
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f,
BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
m_bEnabled = false;
m_bRenderingInitPassed = false;
// move workspaces
std::deque<CWorkspace*> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID) {
wspToMove.push_back(w.get());
if (BACKUPMON) {
// snap cursor
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f,
BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
// move workspaces
std::deque<CWorkspace*> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) {
wspToMove.push_back(w.get());
}
}
}
for (auto& w : wspToMove) {
w->m_szLastMonitor = szName;
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
w->startAnim(true, true, true);
for (auto& w : wspToMove) {
w->m_szLastMonitor = szName;
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
w->startAnim(true, true, true);
}
} else {
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastWindow = nullptr;
g_pCompositor->m_pLastMonitor = nullptr;
}
activeWorkspace = -1;
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
if (!destroy)
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
wlr_output_enable(output, false);
wlr_output_commit(output);
std::erase_if(g_pCompositor->m_vWorkspaces, [&](std::unique_ptr<CWorkspace>& el) { return el->m_iMonitorID == ID; });
if (g_pCompositor->m_pLastMonitor == this)
g_pCompositor->setActiveMonitor(BACKUPMON);
@@ -314,7 +303,6 @@ void CMonitor::onDisconnect() {
g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz;
}
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
}
@@ -333,14 +321,14 @@ void CMonitor::addDamage(const CRegion* rg) {
addDamage(const_cast<CRegion*>(rg)->pixman());
}
void CMonitor::addDamage(const wlr_box* box) {
void CMonitor::addDamage(const CBox* box) {
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
wlr_damage_ring_add_whole(&damage);
g_pCompositor->scheduleFrameForMonitor(this);
}
if (wlr_damage_ring_add_box(&damage, box))
if (wlr_damage_ring_add_box(&damage, const_cast<CBox*>(box)->pWlr()))
g_pCompositor->scheduleFrameForMonitor(this);
}
@@ -369,16 +357,16 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
findAvailableDefaultWS() :
getWorkspaceIDFromString(g_pConfigManager->getDefaultWorkspaceFor(szName), newDefaultWorkspaceName);
if (WORKSPACEID == INT_MAX || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) {
if (WORKSPACEID == WORKSPACE_INVALID || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) {
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.", g_pConfigManager->getDefaultWorkspaceFor(szName).c_str());
Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"{}\" is invalid.", g_pConfigManager->getDefaultWorkspaceFor(szName));
}
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
Debug::log(LOG, "New monitor: WORKSPACEID {}, exists: {}", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor
@@ -392,15 +380,11 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
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);
PNEWWORKSPACE->m_szLastMonitor = "";
}
@@ -436,19 +420,22 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
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;
}
std::shared_ptr<CMonitor>* thisWrapper = nullptr;
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
thisWrapper = &m;
break;
}
}
RASSERT(thisWrapper->get(), "CMonitor::setMirror: Had no wrapper???");
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(*thisWrapper);
}
setupDefaultWS(RULE);
@@ -515,25 +502,20 @@ float CMonitor::getDefaultScale() {
return 1;
}
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal) {
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove) {
if (!pWorkspace)
return;
if (pWorkspace->m_bIsSpecialWorkspace) {
if (specialWorkspaceID != pWorkspace->m_iID) {
Debug::log(LOG, "changeworkspace on special, togglespecialworkspace to id %i", pWorkspace->m_iID);
Debug::log(LOG, "changeworkspace on special, togglespecialworkspace to id {}", pWorkspace->m_iID);
g_pKeybindManager->m_mDispatchers["togglespecialworkspace"](pWorkspace->m_szName == "special" ? "" : pWorkspace->m_szName);
}
return;
}
if (pWorkspace->m_iID == activeWorkspace) {
// in some cases (e.g. workspace from one monitor to another)
// we need to send this
g_pCompositor->deactivateAllWLRWorkspaces(pWorkspace->m_pWlrHandle);
pWorkspace->setActive(true);
if (pWorkspace->m_iID == activeWorkspace)
return;
}
const auto POLDWORKSPACE = g_pCompositor->getWorkspaceByID(activeWorkspace);
@@ -569,14 +551,11 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal) {
g_pCompositor->focusWindow(pWindow);
}
g_pInputManager->simulateMouseMovement();
if (!noMouseMove)
g_pInputManager->simulateMouseMovement();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
// set some flags and fire event
g_pCompositor->deactivateAllWLRWorkspaces(pWorkspace->m_pWlrHandle);
pWorkspace->setActive(true);
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", pWorkspace->m_szName});
EMIT_HOOK_EVENT("workspace", pWorkspace);
}
@@ -584,6 +563,8 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal) {
g_pHyprRenderer->damageMonitor(this);
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
g_pConfigManager->ensureVRR(this);
}
void CMonitor::changeWorkspace(const int& id, bool internal) {
@@ -595,8 +576,10 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
if (!pWorkspace) {
// remove special if exists
if (const auto EXISTINGSPECIAL = g_pCompositor->getWorkspaceByID(specialWorkspaceID); EXISTINGSPECIAL)
if (const auto EXISTINGSPECIAL = g_pCompositor->getWorkspaceByID(specialWorkspaceID); EXISTINGSPECIAL) {
EXISTINGSPECIAL->startAnim(false, false);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + szName});
}
specialWorkspaceID = 0;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
@@ -615,10 +598,21 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
EXISTINGSPECIAL->startAnim(false, false);
}
bool animate = true;
//close if open elsewhere
const auto PMONITORWORKSPACEOWNER = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
if (PMONITORWORKSPACEOWNER->specialWorkspaceID == pWorkspace->m_iID) {
PMONITORWORKSPACEOWNER->specialWorkspaceID = 0;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMONITORWORKSPACEOWNER->szName});
animate = false;
}
// open special
pWorkspace->m_iMonitorID = ID;
specialWorkspaceID = pWorkspace->m_iID;
pWorkspace->startAnim(true, true);
if (animate)
pWorkspace->startAnim(true, true);
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
@@ -633,6 +627,10 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
g_pCompositor->focusWindow(PLAST);
else
g_pInputManager->refocus();
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
g_pHyprRenderer->damageMonitor(this);
}
void CMonitor::setSpecialWorkspace(const int& id) {
@@ -645,3 +643,16 @@ void CMonitor::moveTo(const Vector2D& pos) {
if (!isMirror())
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y);
}
Vector2D CMonitor::middle() {
return vecPosition + vecSize / 2.f;
}
void CMonitor::updateMatrix() {
wlr_matrix_identity(projMatrix.data());
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
wlr_matrix_translate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
wlr_matrix_transform(projMatrix.data(), transform);
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
}
}

View File

@@ -43,6 +43,7 @@ class CMonitor {
float scale = 1;
std::string szName = "";
std::string szDescription = "";
Vector2D vecReservedTopLeft = Vector2D(0, 0);
Vector2D vecReservedBottomRight = Vector2D(0, 0);
@@ -50,29 +51,33 @@ class CMonitor {
drmModeModeInfo customDrmMode = {};
// WLR stuff
wlr_damage_ring damage;
wlr_output* output = nullptr;
float refreshRate = 60;
int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
bool gammaChanged = false;
wlr_damage_ring damage;
wlr_output* output = nullptr;
float refreshRate = 60;
int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
bool gammaChanged = false;
float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0};
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
uint32_t drmFormat = DRM_FORMAT_INVALID;
bool isUnsafeFallback = false;
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false;
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false;
wl_event_source* renderTimer = nullptr; // for RAT
bool RATScheduled = false;
CTimer lastPresentationTimer;
wl_event_source* renderTimer = nullptr; // for RAT
bool RATScheduled = false;
CTimer lastPresentationTimer;
SMonitorRule activeMonitorRule;
SMonitorRule activeMonitorRule;
// mirroring
CMonitor* pMirrorOf = nullptr;
@@ -80,6 +85,18 @@ class CMonitor {
CRegion lastFrameDamage; // stores last frame damage
// for tearing
CWindow* solitaryClient = nullptr;
struct {
bool canTear = false;
bool nextRenderTorn = false;
bool activelyTearing = false;
bool busy = false;
bool frameScheduledWhileBusy = false;
} tearingState;
// for the special workspace. 0 means not open.
int specialWorkspaceID = 0;
@@ -93,28 +110,25 @@ class CMonitor {
DYNLISTENER(monitorCommit);
DYNLISTENER(monitorBind);
// hack: a group = workspaces on a monitor.
// I don't really care lol :P
wlr_ext_workspace_group_handle_v1* pWLRWorkspaceGroupHandle = nullptr;
// methods
void onConnect(bool noRule);
void onDisconnect();
void addDamage(const pixman_region32_t* rg);
void addDamage(const CRegion* rg);
void addDamage(const wlr_box* box);
void setMirror(const std::string&);
bool isMirror();
float getDefaultScale();
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false);
void changeWorkspace(const int& id, bool internal = false);
void setSpecialWorkspace(CWorkspace* const pWorkspace);
void setSpecialWorkspace(const int& id);
void moveTo(const Vector2D& pos);
void onConnect(bool noRule);
void onDisconnect(bool destroy = false);
void addDamage(const pixman_region32_t* rg);
void addDamage(const CRegion* rg);
void addDamage(const CBox* box);
void setMirror(const std::string&);
bool isMirror();
float getDefaultScale();
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false);
void changeWorkspace(const int& id, bool internal = false);
void setSpecialWorkspace(CWorkspace* const pWorkspace);
void setSpecialWorkspace(const int& id);
void moveTo(const Vector2D& pos);
Vector2D middle();
void updateMatrix();
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
// For the list lookup

View File

@@ -1,5 +1,8 @@
#include "Region.hpp"
extern "C" {
#include <wlr/util/box.h>
#include <wlr/util/region.h>
}
CRegion::CRegion() {
pixman_region32_init(&m_rRegion);
@@ -18,6 +21,10 @@ CRegion::CRegion(wlr_box* box) {
pixman_region32_init_rect(&m_rRegion, box->x, box->y, box->width, box->height);
}
CRegion::CRegion(const CBox& box) {
pixman_region32_init_rect(&m_rRegion, box.x, box.y, box.w, box.h);
}
CRegion::CRegion(pixman_box32_t* box) {
pixman_region32_init_rect(&m_rRegion, box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1);
}
@@ -56,6 +63,11 @@ CRegion& CRegion::add(double x, double y, double w, double h) {
return *this;
}
CRegion& CRegion::add(const CBox& other) {
pixman_region32_union_rect(&m_rRegion, &m_rRegion, other.x, other.y, other.w, other.h);
return *this;
}
CRegion& CRegion::subtract(const CRegion& other) {
pixman_region32_subtract(&m_rRegion, &m_rRegion, const_cast<CRegion*>(&other)->pixman());
return *this;
@@ -76,11 +88,30 @@ CRegion& CRegion::invert(pixman_box32_t* box) {
return *this;
}
CRegion& CRegion::invert(const CBox& box) {
pixman_box32 pixmanBox = {box.x, box.y, box.w + box.x, box.h + box.y};
return this->invert(&pixmanBox);
}
CRegion& CRegion::translate(const Vector2D& vec) {
pixman_region32_translate(&m_rRegion, vec.x, vec.y);
return *this;
}
CRegion& CRegion::transform(const wl_output_transform t, double w, double h) {
wlr_region_transform(&m_rRegion, &m_rRegion, t, w, h);
return *this;
}
CRegion CRegion::copy() const {
return CRegion(*this);
}
CRegion& CRegion::scale(float scale) {
wlr_region_scale(&m_rRegion, &m_rRegion, scale);
return *this;
}
std::vector<pixman_box32_t> CRegion::getRects() const {
std::vector<pixman_box32_t> result;
@@ -92,6 +123,46 @@ std::vector<pixman_box32_t> CRegion::getRects() const {
return result;
}
bool CRegion::empty() {
CBox CRegion::getExtents() {
pixman_box32_t* box = pixman_region32_extents(&m_rRegion);
return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1};
}
bool CRegion::containsPoint(const Vector2D& vec) const {
return pixman_region32_contains_point(&m_rRegion, vec.x, vec.y, nullptr);
}
bool CRegion::empty() const {
return !pixman_region32_not_empty(&m_rRegion);
}
Vector2D CRegion::closestPoint(const Vector2D& vec) const {
double bestDist = __FLT_MAX__;
Vector2D leader = vec;
for (auto& box : getRects()) {
double x = 0, y = 0;
if (vec.x >= box.x2)
x = box.x2 - 1;
else if (vec.x < box.x1)
x = box.x1;
else
x = vec.x;
if (vec.y >= box.y2)
y = box.y2 - 1;
else if (vec.y < box.y1)
y = box.y1;
else
y = vec.y;
double distance = sqrt(pow(x, 2) + pow(y, 2));
if (distance < bestDist) {
bestDist = distance;
leader = {x, y};
}
}
return leader;
}

View File

@@ -2,6 +2,7 @@
#include <pixman.h>
#include <vector>
#include "Vector2D.hpp"
#include "Box.hpp"
struct wlr_box;
@@ -15,6 +16,8 @@ class CRegion {
CRegion(double x, double y, double w, double h);
/* Create from a wlr_box */
CRegion(wlr_box* box);
/* Create from a CBox */
CRegion(const CBox& box);
/* Create from a pixman_box32_t */
CRegion(pixman_box32_t* box);
@@ -37,12 +40,20 @@ class CRegion {
CRegion& set(const CRegion& other);
CRegion& add(const CRegion& other);
CRegion& add(double x, double y, double w, double h);
CRegion& add(const CBox& other);
CRegion& subtract(const CRegion& other);
CRegion& intersect(const CRegion& other);
CRegion& intersect(double x, double y, double w, double h);
CRegion& translate(const Vector2D& vec);
CRegion& transform(const wl_output_transform t, double w, double h);
CRegion& invert(pixman_box32_t* box);
bool empty();
CRegion& invert(const CBox& box);
CRegion& scale(float scale);
CBox getExtents();
bool containsPoint(const Vector2D& vec) const;
bool empty() const;
Vector2D closestPoint(const Vector2D& vec) const;
CRegion copy() const;
std::vector<pixman_box32_t> getRects() const;
@@ -52,4 +63,4 @@ class CRegion {
private:
pixman_region32_t m_rRegion;
};
};

View File

@@ -55,7 +55,7 @@ SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* p
PNODE->pParent = pParent;
PNODE->pSubsurface = pSubsurface;
Debug::log(LOG, "Creating a subsurface Node! (pWindow: %lx)", pWindow);
Debug::log(LOG, "Creating a subsurface Node! {}", pWindow);
return PNODE;
}
@@ -63,7 +63,7 @@ SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* p
SSurfaceTreeNode* SubsurfaceTree::createTreeRoot(wlr_surface* pSurface, applyGlobalOffsetFn fn, void* data, CWindow* pWindow) {
const auto PNODE = createTree(pSurface, pWindow);
Debug::log(LOG, "Creating a surfaceTree Root! (pWindow: %lx)", pWindow);
Debug::log(LOG, "Creating a surfaceTree Root! {}", pWindow);
PNODE->offsetfn = fn;
PNODE->globalOffsetData = data;
@@ -83,7 +83,7 @@ void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
}
if (!exists) {
Debug::log(ERR, "Tried to remove a SurfaceTreeNode that doesn't exist?? (Node %lx)", pNode);
Debug::log(ERR, "Tried to remove a SurfaceTreeNode that doesn't exist?? (Node {:x})", (uintptr_t)pNode);
return;
}
@@ -98,8 +98,9 @@ void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
// damage
if (pNode->pSurface && pNode->pSurface->exists()) {
wlr_box extents = {};
wlr_surface_get_extends(pNode->pSurface->wlr(), &extents);
CBox extents = {};
wlr_surface_get_extends(pNode->pSurface->wlr(), extents.pWlr());
extents.applyFromWlr();
int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly);
@@ -145,7 +146,7 @@ void Events::listener_newSubsurfaceNode(void* owner, void* data) {
const auto PNEWSUBSURFACE = &pNode->childSubsurfaces.emplace_back();
Debug::log(LOG, "Added a new subsurface %lx", PSUBSURFACE);
Debug::log(LOG, "Added a new subsurface {:x}", (uintptr_t)PSUBSURFACE);
PNEWSUBSURFACE->pSubsurface = PSUBSURFACE;
PNEWSUBSURFACE->pParent = pNode;
@@ -174,7 +175,7 @@ void Events::listener_mapSubsurface(void* owner, void* data) {
if (subsurface->pChild)
return;
Debug::log(LOG, "Subsurface %lx mapped", subsurface->pSubsurface);
Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface);
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
}
@@ -182,7 +183,7 @@ void Events::listener_mapSubsurface(void* owner, void* data) {
void Events::listener_unmapSubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
Debug::log(LOG, "Subsurface %lx unmapped", subsurface);
Debug::log(LOG, "Subsurface {:x} unmapped", (uintptr_t)subsurface);
if (subsurface->pSubsurface->surface == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons();
@@ -198,7 +199,7 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
int lx = 0, ly = 0;
addSurfaceGlobalOffset(PNODE, &lx, &ly);
wlr_box extents = {lx, ly, 0, 0};
CBox extents = {lx, ly, 0, 0};
extents.width = PNODE->pSurface->wlr()->current.width;
extents.height = PNODE->pSurface->wlr()->current.height;
@@ -219,9 +220,11 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
// no damaging if it's not visible
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from %lx because it's invisible.", pNode->pWindowOwner);
Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner);
return;
}
@@ -243,8 +246,37 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
}
}
if (pNode->pSurface && pNode->pSurface->exists())
if (pNode->pSurface && pNode->pSurface->exists()) {
g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE);
if (pNode->lastSize != Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} && pNode->pWindowOwner)
g_pHyprRenderer->damageWindow(pNode->pWindowOwner);
}
if (pNode->pWindowOwner) {
if (pNode->pWindowOwner->m_bIsX11)
pNode->pWindowOwner->m_vReportedSize = pNode->pWindowOwner->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
// tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID);
if (PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
CRegion damageBox;
wlr_surface_get_effective_damage(pNode->pSurface->wlr(), damageBox.pixman());
if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) {
PMONITOR->tearingState.frameScheduledWhileBusy = true;
} else {
PMONITOR->tearingState.nextRenderTorn = true;
g_pHyprRenderer->renderMonitor(PMONITOR);
}
}
}
}
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
}
void Events::listener_destroySubsurface(void* owner, void* data) {
@@ -254,7 +286,7 @@ void Events::listener_destroySubsurface(void* owner, void* data) {
SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
}
Debug::log(LOG, "Subsurface %lx destroyed", subsurface);
Debug::log(LOG, "Subsurface {:x} destroyed", (uintptr_t)subsurface);
subsurface->hyprListener_destroy.removeCallback();
subsurface->hyprListener_map.removeCallback();
@@ -266,7 +298,7 @@ void Events::listener_destroySubsurface(void* owner, void* data) {
void Events::listener_destroySubsurfaceNode(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
Debug::log(LOG, "Subsurface Node %lx destroyed", pNode);
Debug::log(LOG, "Subsurface Node {:x} destroyed", (uintptr_t)pNode);
for (auto& c : pNode->childSubsurfaces)
destroySubsurface(&c);

View File

@@ -26,6 +26,8 @@ struct SSurfaceTreeNode {
void* globalOffsetData;
CWindow* pWindowOwner = nullptr;
Vector2D lastSize;
//
bool operator==(const SSurfaceTreeNode& rhs) const {
return pSurface == rhs.pSurface;

37
src/helpers/VarList.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "MiscFunctions.hpp"
#include "VarList.hpp"
#include <ranges>
#include <algorithm>
CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) {
if (in.empty())
m_vArgs.emplace_back("");
std::string args{in};
size_t idx = 0;
size_t pos = 0;
std::ranges::replace_if(
args, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0);
for (const auto& s : args | std::views::split(0)) {
if (removeEmpty && s.empty())
continue;
if (++idx == lastArgNo) {
m_vArgs.emplace_back(removeBeginEndSpacesTabs(in.substr(pos)));
break;
}
pos += s.size() + 1;
m_vArgs.emplace_back(removeBeginEndSpacesTabs(std::string_view{s}.data()));
}
}
std::string CVarList::join(const std::string& joiner, size_t from, size_t to) const {
size_t last = to == 0 ? size() : to;
std::string rolling;
for (size_t i = from; i < last; ++i) {
rolling += m_vArgs[i] + (i + 1 < last ? joiner : "");
}
return rolling;
}

55
src/helpers/VarList.hpp Normal file
View File

@@ -0,0 +1,55 @@
#pragma once
#include <functional>
#include <vector>
#include <string>
#include "../macros.hpp"
class CVarList {
public:
/** Split string into arg list
@param lastArgNo stop splitting after argv reaches maximum size, last arg will contain rest of unsplit args
@param delim if delimiter is 's', use std::isspace
@param removeEmpty remove empty args from argv
*/
CVarList(const std::string& in, const size_t maxSize = 0, const char delim = ',', const bool removeEmpty = false);
~CVarList() = default;
size_t size() const {
return m_vArgs.size();
}
std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const;
void map(std::function<void(std::string&)> func) {
for (auto& s : m_vArgs)
func(s);
}
void append(const std::string arg) {
m_vArgs.emplace_back(arg);
}
std::string operator[](const size_t& idx) const {
if (idx >= m_vArgs.size())
return "";
return m_vArgs[idx];
}
// for range-based loops
std::vector<std::string>::iterator begin() {
return m_vArgs.begin();
}
std::vector<std::string>::const_iterator begin() const {
return m_vArgs.begin();
}
std::vector<std::string>::iterator end() {
return m_vArgs.end();
}
std::vector<std::string>::const_iterator end() const {
return m_vArgs.end();
}
private:
std::vector<std::string> m_vArgs;
};

View File

@@ -28,6 +28,10 @@ Vector2D Vector2D::floor() const {
return Vector2D(std::floor(x), std::floor(y));
}
Vector2D Vector2D::round() const {
return Vector2D(std::round(x), std::round(y));
}
Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const {
return Vector2D(std::clamp(this->x, min.x, max.x < min.x ? INFINITY : max.x), std::clamp(this->y, min.y, max.y < min.y ? INFINITY : max.y));
}
@@ -45,3 +49,7 @@ bool Vector2D::inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
}
double Vector2D::size() const {
return std::sqrt(x * x + y * y);
}

View File

@@ -1,6 +1,8 @@
#pragma once
#include <cmath>
#include <format>
#include "../macros.hpp"
class Vector2D {
public:
@@ -20,10 +22,13 @@ class Vector2D {
Vector2D operator-(const Vector2D& a) const {
return Vector2D(this->x - a.x, this->y - a.y);
}
Vector2D operator*(const float& a) const {
Vector2D operator-() const {
return Vector2D(-this->x, -this->y);
}
Vector2D operator*(const double& a) const {
return Vector2D(this->x * a, this->y * a);
}
Vector2D operator/(const float& a) const {
Vector2D operator/(const double& a) const {
return Vector2D(this->x / a, this->y / a);
}
@@ -50,12 +55,76 @@ class Vector2D {
bool operator<(const Vector2D& a) const {
return this->x < a.x && this->y < a.y;
}
Vector2D& operator+=(const Vector2D& a) {
this->x += a.x;
this->y += a.y;
return *this;
}
Vector2D& operator-=(const Vector2D& a) {
this->x -= a.x;
this->y -= a.y;
return *this;
}
Vector2D& operator*=(const Vector2D& a) {
this->x *= a.x;
this->y *= a.y;
return *this;
}
Vector2D& operator/=(const Vector2D& a) {
this->x /= a.x;
this->y /= a.y;
return *this;
}
Vector2D& operator*=(const double& a) {
this->x *= a;
this->y *= a;
return *this;
}
Vector2D& operator/=(const double& a) {
this->x /= a;
this->y /= a;
return *this;
}
double distance(const Vector2D& other) const;
double size() const;
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const;
Vector2D floor() const;
Vector2D round() const;
bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const;
};
/**
format specification
- 'j', as json array
- 'X', same as std::format("{}x{}", vec.x, vec.y)
- number, floating point precision, use `0` to format as integer
*/
template <typename CharT>
struct std::formatter<Vector2D, CharT> : std::formatter<CharT> {
bool formatJson = false;
bool formatX = false;
std::string precision = "";
FORMAT_PARSE(FORMAT_FLAG('j', formatJson) //
FORMAT_FLAG('X', formatX) //
FORMAT_NUMBER(precision),
Vector2D)
template <typename FormatContext>
auto format(const Vector2D& vec, FormatContext& ctx) const {
std::string formatString = precision.empty() ? "{}" : std::format("{{:.{}f}}", precision);
if (formatJson)
formatString = std::format("[{0}, {0}]", formatString);
else if (formatX)
formatString = std::format("{0}x{0}", formatString);
else
formatString = std::format("[Vector2D: x: {0}, y: {0}]", formatString);
try {
string buf = std::vformat(formatString, std::make_format_args(vec.x, vec.y));
return std::format_to(ctx.out(), "{}", buf);
} catch (std::format_error& e) { return std::format_to(ctx.out(), "[{}, {}]", vec.x, vec.y); }
}
};

View File

@@ -1,5 +1,6 @@
#include "WLClasses.hpp"
#include "../config/ConfigManager.hpp"
#include "../Compositor.hpp"
SLayerSurface::SLayerSurface() {
alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE);
@@ -7,6 +8,11 @@ SLayerSurface::SLayerSurface() {
alpha.registerVar();
}
SLayerSurface::~SLayerSurface() {
g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first == this; });
}
void SLayerSurface::applyRules() {
noAnimations = false;
forceBlur = false;
@@ -19,7 +25,7 @@ void SLayerSurface::applyRules() {
noAnimations = true;
else if (rule.rule == "blur")
forceBlur = true;
else if (rule.rule.find("ignorealpha") == 0 || rule.rule.find("ignorezero") == 0) {
else if (rule.rule.starts_with("ignorealpha") || rule.rule.starts_with("ignorezero")) {
const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
std::string alphaValue = "";
if (FIRST_SPACE_POS != std::string::npos)
@@ -30,11 +36,87 @@ void SLayerSurface::applyRules() {
if (!alphaValue.empty())
ignoreAlphaValue = std::stof(alphaValue);
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
} else if (rule.rule.find("xray") == 0) {
} else if (rule.rule.starts_with("xray")) {
CVarList vars{rule.rule, 0, ' '};
try {
xray = configStringToInt(vars[1]);
} catch (...) {}
}
}
}
CRegion SConstraint::getLogicCoordsRegion() {
CRegion result;
if (!constraint)
return result;
const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface);
if (!PWINDOWOWNER)
return result;
result.add(&constraint->region); // surface-local coords
if (!PWINDOWOWNER->m_bIsX11) {
result.translate(PWINDOWOWNER->m_vRealPosition.goalv());
return result;
}
const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() :
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y});
const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : g_pCompositor->getMonitorFromVector(COORDS);
if (!PMONITOR)
return CRegion{};
result.scale(PMONITOR->xwaylandScale);
result.translate(COORDS);
return result;
}
Vector2D SConstraint::getLogicConstraintPos() {
if (!constraint)
return {};
const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface);
if (!PWINDOWOWNER)
return {};
if (!PWINDOWOWNER->m_bIsX11)
return PWINDOWOWNER->m_vRealPosition.goalv();
const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() :
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y});
return COORDS;
}
Vector2D SConstraint::getLogicConstraintSize() {
if (!constraint)
return {};
const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface);
if (!PWINDOWOWNER)
return {};
if (!PWINDOWOWNER->m_bIsX11)
return PWINDOWOWNER->m_vRealSize.goalv();
const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ?
g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) :
g_pCompositor->getMonitorFromVector(g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y}));
if (!PMONITOR)
return {};
const auto SIZE = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealSize.goalv() :
Vector2D{PWINDOWOWNER->m_uSurface.xwayland->width, PWINDOWOWNER->m_uSurface.xwayland->height} * PMONITOR->xwaylandScale;
return SIZE;
}

View File

@@ -16,6 +16,7 @@ struct SLayerRule {
struct SLayerSurface {
SLayerSurface();
~SLayerSurface();
void applyRules();
@@ -33,7 +34,7 @@ struct SLayerSurface {
DYNLISTENER(commitLayerSurface);
DYNLISTENER(newPopup);
wlr_box geometry = {0, 0, 0, 0};
CBox geometry = {0, 0, 0, 0};
Vector2D position;
zwlr_layer_shell_v1_layer layer;
@@ -65,12 +66,12 @@ class CMonitor;
struct SRenderData {
CMonitor* pMonitor;
timespec* when;
int x, y;
double x, y;
// for iters
void* data = nullptr;
wlr_surface* surface = nullptr;
int w, h;
double w, h;
// for rounding
bool dontRound = true;
@@ -166,13 +167,20 @@ struct SConstraint {
SMouse* pMouse = nullptr;
wlr_pointer_constraint_v1* constraint = nullptr;
bool hintSet = false;
Vector2D positionHint; // the position hint, but will be set to the current cursor pos if not set.
bool active = false;
bool hintSet = false;
Vector2D positionHint = {-1, -1}; // the position hint, but will use cursorPosOnActivate if unset
Vector2D cursorPosOnActivate = {-1, -1};
DYNLISTENER(setConstraintRegion);
DYNLISTENER(destroyConstraint);
bool operator==(const SConstraint& b) const {
CRegion getLogicCoordsRegion();
Vector2D getLogicConstraintPos();
Vector2D getLogicConstraintSize();
bool operator==(const SConstraint& b) const {
return constraint == b.constraint;
}
};
@@ -310,8 +318,8 @@ struct SSwipeGesture {
double delta = 0;
int initialDirection = 0;
float avgSpeed = 0;
int speedPoints = 0;
float avgSpeed = 0;
int speedPoints = 0;
CMonitor* pMonitor = nullptr;
};
@@ -386,3 +394,14 @@ struct SSwitchDevice {
return pWlrDevice == other.pWlrDevice;
}
};
struct STearingController {
wlr_tearing_control_v1* pWlrHint = nullptr;
DYNLISTENER(set);
DYNLISTENER(destroy);
bool operator==(const STearingController& other) {
return pWlrHint == other.pWlrHint;
}
};

View File

@@ -2,11 +2,18 @@
#include "MiscFunctions.hpp"
#include <string>
#include "../debug/Log.hpp"
#include "Watchdog.hpp"
void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
pWrap->m_pSelf->emit(data);
g_pWatchdog->startWatching();
try {
pWrap->m_pSelf->emit(data);
} catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); }
g_pWatchdog->endWatching();
}
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {
@@ -25,7 +32,7 @@ CHyprWLListener::~CHyprWLListener() {
void CHyprWLListener::removeCallback() {
if (isConnected()) {
Debug::log(LOG, "Callback %lx -> %lx, %s removed.", &m_pCallback, &m_pOwner, m_szAuthor.c_str());
Debug::log(LOG, "Callback {:x} -> {:x}, {} removed.", (uintptr_t)&m_pCallback, (uintptr_t)&m_pOwner, m_szAuthor);
wl_list_remove(&m_swWrapper.m_sListener.link);
wl_list_init(&m_swWrapper.m_sListener.link);
}
@@ -50,4 +57,4 @@ void CHyprWLListener::initCallback(wl_signal* pSignal, std::function<void(void*,
void CHyprWLListener::emit(void* data) {
m_pCallback(m_pOwner, data);
}
}

View File

@@ -27,19 +27,49 @@ wlr_surface* CWLSurface::wlr() const {
return m_pWLRSurface;
}
bool CWLSurface::small() const {
if (!m_pOwner || !exists())
return false;
return m_pOwner->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || m_pOwner->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1;
}
Vector2D CWLSurface::correctSmallVec() const {
if (!m_pOwner || !exists() || !small() || m_bFillIgnoreSmall)
return {};
const auto SIZE = getViewporterCorrectedSize();
return Vector2D{(m_pOwner->m_vReportedSize.x - SIZE.x) / 2, (m_pOwner->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) *
(m_pOwner->m_vRealSize.vec() / m_pOwner->m_vReportedSize);
}
Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists())
return {};
return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} :
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
}
void CWLSurface::destroy() {
if (!m_pWLRSurface)
return;
hyprListener_destroy.removeCallback();
m_pWLRSurface->data = nullptr;
m_pOwner = nullptr;
if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
g_pCompositor->m_pLastFocus = nullptr;
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_pWLRSurface = nullptr;
Debug::log(LOG, "CWLSurface %lx called destroy()", this);
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
}
void CWLSurface::init() {
@@ -53,5 +83,5 @@ void CWLSurface::init() {
hyprListener_destroy.initCallback(
&m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
Debug::log(LOG, "CWLSurface %lx called init()", this);
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
}

View File

@@ -1,6 +1,9 @@
#pragma once
#include "../defines.hpp"
class CWindow;
class CWLSurface {
public:
CWLSurface() = default;
@@ -10,20 +13,29 @@ class CWLSurface {
void assign(wlr_surface* pSurface);
void unassign();
CWLSurface(const CWLSurface&) = delete;
CWLSurface(CWLSurface&&) = delete;
CWLSurface(const CWLSurface&) = delete;
CWLSurface(CWLSurface&&) = delete;
CWLSurface& operator=(const CWLSurface&) = delete;
CWLSurface& operator=(CWLSurface&&) = delete;
CWLSurface& operator=(CWLSurface&&) = delete;
wlr_surface* wlr() const;
bool exists() const;
bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D getViewporterCorrectedSize() const;
CWLSurface& operator=(wlr_surface* pSurface) {
destroy();
m_pWLRSurface = pSurface;
init();
// allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false;
return *this;
// if present, means this is a base surface of a window. Cleaned on unassign()
CWindow* m_pOwner = nullptr;
CWLSurface& operator=(wlr_surface* pSurface) {
destroy();
m_pWLRSurface = pSurface;
init();
return *this;
}
bool operator==(const CWLSurface& other) const {
@@ -38,6 +50,10 @@ class CWLSurface {
return exists();
}
static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) {
return (CWLSurface*)pSurface->data;
}
private:
wlr_surface* m_pWLRSurface = nullptr;

59
src/helpers/Watchdog.cpp Normal file
View File

@@ -0,0 +1,59 @@
#include "Watchdog.hpp"
#include <signal.h>
#include "config/ConfigManager.hpp"
CWatchdog::~CWatchdog() {
m_bExitThread = true;
m_bNotified = true;
m_cvWatchdogCondition.notify_all();
m_pWatchdog.reset();
}
CWatchdog::CWatchdog() {
m_iMainThreadPID = pthread_self();
m_pWatchdog = std::make_unique<std::thread>([this] {
static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
while (1337) {
std::unique_lock lk(m_mWatchdogMutex);
if (!m_bWillWatch)
m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified; });
else {
if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false)
pthread_kill(m_iMainThreadPID, SIGUSR1);
}
if (m_bExitThread)
break;
m_bWatching = false;
m_bNotified = false;
}
});
m_pWatchdog->detach();
}
void CWatchdog::startWatching() {
static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
if (*PTIMEOUT == 0)
return;
m_tTriggered = std::chrono::high_resolution_clock::now();
m_bWillWatch = true;
m_bWatching = true;
m_bNotified = true;
m_cvWatchdogCondition.notify_all();
}
void CWatchdog::endWatching() {
m_bWatching = false;
m_bWillWatch = false;
m_bNotified = true;
m_cvWatchdogCondition.notify_all();
}

32
src/helpers/Watchdog.hpp Normal file
View File

@@ -0,0 +1,32 @@
#pragma once
#include <memory>
#include <chrono>
#include <thread>
#include <condition_variable>
class CWatchdog {
public:
// must be called from the main thread
CWatchdog();
~CWatchdog();
void startWatching();
void endWatching();
private:
std::chrono::high_resolution_clock::time_point m_tTriggered;
pthread_t m_iMainThreadPID = 0;
bool m_bWatching = false;
bool m_bWillWatch = false;
std::unique_ptr<std::thread> m_pWatchdog;
std::mutex m_mWatchdogMutex;
bool m_bNotified = false;
bool m_bExitThread = false;
std::condition_variable m_cvWatchdogCondition;
};
inline std::unique_ptr<CWatchdog> g_pWatchdog;

View File

@@ -13,18 +13,6 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
m_szName = name;
m_bIsSpecialWorkspace = special;
if (!special) {
m_pWlrHandle = wlr_ext_workspace_handle_v1_create(PMONITOR->pWLRWorkspaceGroupHandle);
// set geometry here cuz we can
wl_array_init(&m_wlrCoordinateArr);
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.x;
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.y;
wlr_ext_workspace_handle_v1_set_coordinates(m_pWlrHandle, &m_wlrCoordinateArr);
wlr_ext_workspace_handle_v1_set_hidden(m_pWlrHandle, false);
wlr_ext_workspace_handle_v1_set_urgent(m_pWlrHandle, false);
}
m_vRenderOffset.m_pWorkspace = this;
m_vRenderOffset.create(AVARTYPE_VECTOR, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"),
nullptr, AVARDAMAGE_ENTIRE);
@@ -43,22 +31,17 @@ CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
CWorkspace::~CWorkspace() {
m_vRenderOffset.unregister();
Debug::log(LOG, "Destroying workspace ID %d", m_iID);
if (m_pWlrHandle) {
wlr_ext_workspace_handle_v1_set_active(m_pWlrHandle, false);
wlr_ext_workspace_handle_v1_destroy(m_pWlrHandle);
m_pWlrHandle = nullptr;
}
Debug::log(LOG, "Destroying workspace ID {}", m_iID);
g_pEventManager->postEvent({"destroyworkspace", m_szName});
EMIT_HOOK_EVENT("destroyWorkspace", this);
}
void CWorkspace::startAnim(bool in, bool left, bool instant) {
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
const auto PWORKSPACEGAP = &g_pConfigManager->getConfigValuePtr("general:gaps_workspaces")->intValue;
if (ANIMSTYLE.find("slidefade") == 0) {
if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
float movePerc = 100.f;
@@ -72,7 +55,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
m_fAlpha.setValueAndWarp(1.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
if (ANIMSTYLE.find("slidefadevert") == 0) {
if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
@@ -108,26 +91,28 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} else if (ANIMSTYLE == "slidevert") {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y));
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? YDISTANCE : -YDISTANCE));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(0, left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y);
m_vRenderOffset = Vector2D(0, left ? -YDISTANCE : YDISTANCE);
}
} else {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x, 0));
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x, 0);
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0);
}
}
@@ -149,31 +134,11 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
}
void CWorkspace::setActive(bool on) {
if (m_pWlrHandle) {
wlr_ext_workspace_handle_v1_set_active(m_pWlrHandle, on);
}
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
void CWorkspace::moveToMonitor(const int& id) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(id);
if (!PMONITOR || m_bIsSpecialWorkspace)
return;
wlr_ext_workspace_handle_v1_set_active(m_pWlrHandle, false);
wlr_ext_workspace_handle_v1_destroy(m_pWlrHandle);
m_pWlrHandle = wlr_ext_workspace_handle_v1_create(PMONITOR->pWLRWorkspaceGroupHandle);
// set geometry here cuz we can
wl_array_init(&m_wlrCoordinateArr);
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.x;
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.y;
wlr_ext_workspace_handle_v1_set_coordinates(m_pWlrHandle, &m_wlrCoordinateArr);
wlr_ext_workspace_handle_v1_set_hidden(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());
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
CWindow* CWorkspace::getLastFocusedWindow() {
@@ -190,7 +155,7 @@ void CWorkspace::rememberPrevWorkspace(const CWorkspace* prev) {
return;
}
if (prev->m_sPrevWorkspace.iID == m_sPrevWorkspace.iID) {
if (prev->m_iID == m_iID) {
Debug::log(LOG, "Tried to set prev workspace to the same as current one");
return;
}

View File

@@ -3,10 +3,10 @@
#include "AnimatedVariable.hpp"
#include <string>
#include "../defines.hpp"
#include "../wlrunstable/wlr_ext_workspace_v1.hpp"
enum eFullscreenMode : uint8_t {
FULLSCREEN_FULL = 0,
enum eFullscreenMode : int8_t {
FULLSCREEN_INVALID = -1,
FULLSCREEN_FULL = 0,
FULLSCREEN_MAXIMIZED
};
@@ -29,12 +29,10 @@ class CWorkspace {
std::string name = "";
} m_sPrevWorkspace;
bool m_bHasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL;
bool m_bHasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL;
wlr_ext_workspace_handle_v1* m_pWlrHandle = nullptr;
wl_array m_wlrCoordinateArr;
wl_array m_wlrCoordinateArr;
// for animations
CAnimatedVariable m_vRenderOffset;
@@ -51,12 +49,12 @@ class CWorkspace {
bool m_bDefaultFloating = false;
bool m_bDefaultPseudo = false;
// don't destroy in sanity check
bool m_bIndestructible = false;
// last monitor (used on reconnect)
std::string m_szLastMonitor = "";
// Whether the user configured command for on-created-empty has been executed, if any
bool m_bOnCreatedEmptyExecuted = false;
void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on);

View File

@@ -5,7 +5,7 @@ CHyprError::CHyprError() {
m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_NONE);
m_fFadeOpacity.registerVar();
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, std::any param) {
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (!m_bIsCreated)
return;
@@ -13,7 +13,7 @@ CHyprError::CHyprError() {
m_bMonitorChanged = true;
});
g_pHookSystem->hookDynamic("preRender", [&](void* self, std::any param) {
g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any param) {
if (!m_bIsCreated)
return;
@@ -154,7 +154,7 @@ void CHyprError::draw() {
const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor;
wlr_box monbox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
CBox monbox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
m_bDamageBox.x = (int)PMONITOR->vecPosition.x;
m_bDamageBox.y = (int)PMONITOR->vecPosition.y;

View File

@@ -23,7 +23,7 @@ class CHyprError {
bool m_bIsCreated = false;
CTexture m_tTexture;
CAnimatedVariable m_fFadeOpacity;
wlr_box m_bDamageBox = {0, 0, 0, 0};
CBox m_bDamageBox = {0, 0, 0, 0};
bool m_bMonitorChanged = false;
};

View File

@@ -47,7 +47,6 @@ extern "C" {
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_layer_shell_v1.h>
@@ -70,8 +69,7 @@ extern "C" {
#include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_input_inhibitor.h>
#include <wlr/types/wlr_damage_ring.h>
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
@@ -105,6 +103,11 @@ extern "C" {
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_tearing_control_v1.h>
#include <wlr/util/box.h>
#include <wlr/util/transform.h>
#include <wlr/render/swapchain.h>
#include <wlr/render/egl.h>
#include <libdrm/drm_fourcc.h>
@@ -145,6 +148,5 @@ extern "C" {
#endif
#include "helpers/Vector2D.hpp"
#include "ext-workspace-unstable-v1-protocol.h"
#include "wlrunstable/wlr_ext_workspace_v1.hpp"
#include "helpers/Box.hpp"
#include "SharedDefs.hpp"

View File

@@ -1,17 +1,15 @@
#include "DwindleLayout.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../Compositor.hpp"
void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) {
if (children[0]) {
const auto REVERSESPLITRATIO = 2.f - splitRatio;
static auto* const PSMARTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:smart_split")->intValue;
static auto* const PPRESERVESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:preserve_split")->intValue;
static auto* const PFLMULT = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
if (*PPRESERVESPLIT == 0 && *PSMARTSPLIT == 0) {
splitTop = size.y * *PFLMULT > size.x;
splitTop = box.h * *PFLMULT > box.w;
}
if (verticalOverride == true)
@@ -23,16 +21,14 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
if (SPLITSIDE) {
// split left/right
children[0]->position = position;
children[0]->size = Vector2D(size.x / 2.f * splitRatio, size.y);
children[1]->position = Vector2D(position.x + size.x / 2.f * splitRatio, position.y);
children[1]->size = Vector2D(size.x / 2.f * REVERSESPLITRATIO, size.y);
const float FIRSTSIZE = box.w / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h};
children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h};
} else {
// split top/bottom
children[0]->position = position;
children[0]->size = Vector2D(size.x, size.y / 2.f * splitRatio);
children[1]->position = Vector2D(position.x, position.y + size.y / 2.f * splitRatio);
children[1]->size = Vector2D(size.x, size.y / 2.f * REVERSESPLITRATIO);
const float FIRSTSIZE = box.h / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE};
children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE};
}
children[0]->recalcSizePosRecursive(force);
@@ -104,21 +100,24 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
}
if (!PMONITOR) {
Debug::log(ERR, "Orphaned Node %lx (workspace ID: %i)!!", pNode, pNode->workspaceID);
Debug::log(ERR, "Orphaned Node {}!!", pNode);
return;
}
// for gaps outer
const bool DISPLAYLEFT = STICKS(pNode->position.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool DISPLAYRIGHT = STICKS(pNode->position.x + pNode->size.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const bool DISPLAYLEFT = STICKS(pNode->box.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool DISPLAYRIGHT = STICKS(pNode->box.x + pNode->box.w, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(pNode->box.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYBOTTOM = STICKS(pNode->box.y + pNode->box.h, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const auto PWINDOW = pNode->pWindow;
// get specific gaps and rules for this workspace,
// if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID));
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return;
PWINDOW->updateSpecialRenderData();
static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
@@ -129,13 +128,16 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
if (!g_pCompositor->windowExists(PWINDOW) || !PWINDOW->m_bIsMapped) {
Debug::log(ERR, "Node %lx holding invalid window %lx!!", pNode, PWINDOW);
Debug::log(ERR, "Node {} holding invalid {}!!", pNode, PWINDOW);
onWindowRemovedTiling(PWINDOW);
return;
}
PWINDOW->m_vSize = pNode->size;
PWINDOW->m_vPosition = pNode->position;
CBox nodeBox = pNode->box;
nodeBox.round();
PWINDOW->m_vSize = nodeBox.size();
PWINDOW->m_vPosition = nodeBox.pos();
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID);
@@ -156,6 +158,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
PWINDOW->updateWindowDecos();
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
return;
}
@@ -203,10 +207,13 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
// if special, we adjust the coords a bit
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue;
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
PWINDOW->m_vRealSize = calcSize * *PSCALEFACTOR;
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
wb.round(); // avoid rounding mess
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize * *PSCALEFACTOR);
PWINDOW->m_vRealPosition = wb.pos();
PWINDOW->m_vRealSize = wb.size();
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
} else {
PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos;
@@ -226,7 +233,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
PWINDOW->updateWindowDecos();
}
void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating)
return;
@@ -238,6 +245,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
static auto* const PUSEACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:use_active_for_splits")->intValue;
static auto* const PDEFAULTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:default_split_ratio")->floatValue;
if (direction != DIRECTION_DEFAULT && overrideDirection == DIRECTION_DEFAULT)
overrideDirection = direction;
// Populate the node with our window's data
PNODE->workspaceID = pWindow->m_iWorkspaceID;
PNODE->pWindow = pWindow;
@@ -245,11 +255,13 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
PNODE->layout = this;
SDwindleNodeData* OPENINGON;
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromCursor();
const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);
if (PMONITOR->ID == MONFROMCURSOR->ID &&
(PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(MOUSECOORDS));
// happens on reserved area
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
@@ -260,7 +272,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) {
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
} else {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(MOUSECOORDS));
}
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
@@ -268,7 +280,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
} else
OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID);
Debug::log(LOG, "OPENINGON: %lx, Workspace: %i, Monitor: %i", OPENINGON, PNODE->workspaceID, PMONITOR->ID);
Debug::log(LOG, "OPENINGON: {}, Monitor: {}", OPENINGON, PMONITOR->ID);
if (OPENINGON && OPENINGON->workspaceID != PNODE->workspaceID) {
// special workspace handling
@@ -276,7 +288,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
}
// first, check if OPENINGON isn't too big.
const auto PREDSIZEMAX = OPENINGON ? Vector2D(OPENINGON->size.x, OPENINGON->size.y) : PMONITOR->vecSize;
const auto PREDSIZEMAX = OPENINGON ? Vector2D(OPENINGON->box.w, OPENINGON->box.h) : PMONITOR->vecSize;
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
@@ -285,17 +297,10 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* 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);
}
// last fail-safe to avoid duplicate fullscreens
if ((!OPENINGON || OPENINGON->pWindow == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) {
for (auto& node : m_lDwindleNodesData) {
if (node.workspaceID == PNODE->workspaceID && node.pWindow != pWindow) {
if (node.workspaceID == PNODE->workspaceID && node.pWindow != nullptr && node.pWindow != pWindow) {
OPENINGON = &node;
break;
}
@@ -304,42 +309,45 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
// if it's the first, it's easy. Make it fullscreen.
if (!OPENINGON || OPENINGON->pWindow == pWindow) {
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
PNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
PNODE->box = CBox{PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
applyNodeDataToWindow(PNODE);
pWindow->applyGroupRules();
return;
}
if (!m_vOverrideFocalPoint && g_pInputManager->m_bWasDraggingWindow) {
for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS))
return;
break;
}
}
}
// if it's a group, add the window
if (OPENINGON->pWindow->m_sGroupData.pNextWindow && !OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked &&
!g_pKeybindManager->m_bGroupsLocked) { // target is an unlocked group
if (OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow) && !m_vOverrideFocalPoint) { // we are not moving window
m_lDwindleNodesData.remove(*PNODE);
if (!pWindow->m_sGroupData.pNextWindow) { // source is not a group
m_lDwindleNodesData.remove(*PNODE);
OPENINGON->pWindow->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
g_pCompositor->focusWindow(pWindow);
return;
}
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
if (!pWindow->getGroupHead()->m_sGroupData.locked) { // source is an unlocked group
m_lDwindleNodesData.remove(*PNODE);
OPENINGON->pWindow->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
g_pCompositor->focusWindow(pWindow);
return;
}
return;
}
// If it's not, get the node under our cursor
@@ -348,8 +356,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
const auto NEWPARENT = &m_lDwindleNodesData.back();
// make the parent have the OPENINGON's stats
NEWPARENT->position = OPENINGON->position;
NEWPARENT->size = OPENINGON->size;
NEWPARENT->box = OPENINGON->box;
NEWPARENT->workspaceID = OPENINGON->workspaceID;
NEWPARENT->pParent = OPENINGON->pParent;
NEWPARENT->isNode = true; // it is a node
@@ -358,11 +365,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
const auto PWIDTHMULTIPLIER = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
// if cursor over first child, make it first, etc
const auto SIDEBYSIDE = NEWPARENT->size.x > NEWPARENT->size.y * *PWIDTHMULTIPLIER;
const auto SIDEBYSIDE = NEWPARENT->box.w > NEWPARENT->box.h * *PWIDTHMULTIPLIER;
NEWPARENT->splitTop = !SIDEBYSIDE;
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
static auto* const PFORCESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:force_split")->intValue;
static auto* const PERMANENTDIRECTIONOVERRIDE = &g_pConfigManager->getConfigValuePtr("dwindle:permanent_direction_override")->intValue;
static auto* const PSMARTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:smart_split")->intValue;
@@ -371,7 +376,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
bool verticalOverride = false;
// let user select position -> top, right, bottom, left
if (overrideDirection != OneTimeFocus::NOFOCUS) {
if (overrideDirection != DIRECTION_DEFAULT) {
// this is horizontal
if (overrideDirection % 2 == 0)
@@ -390,13 +395,13 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
// whether or not the override persists after opening one window
if (*PERMANENTDIRECTIONOVERRIDE == 0)
overrideDirection = OneTimeFocus::NOFOCUS;
overrideDirection = DIRECTION_DEFAULT;
} else if (*PSMARTSPLIT == 1) {
const auto tl = NEWPARENT->position;
const auto tr = NEWPARENT->position + Vector2D(NEWPARENT->size.x, 0);
const auto bl = NEWPARENT->position + Vector2D(0, NEWPARENT->size.y);
const auto br = NEWPARENT->position + NEWPARENT->size;
const auto cc = NEWPARENT->position + NEWPARENT->size / 2;
const auto tl = NEWPARENT->box.pos();
const auto tr = NEWPARENT->box.pos() + Vector2D(NEWPARENT->box.w, 0);
const auto bl = NEWPARENT->box.pos() + Vector2D(0, NEWPARENT->box.h);
const auto br = NEWPARENT->box.pos() + NEWPARENT->box.size();
const auto cc = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
if (MOUSECOORDS.inTriangle(tl, tr, cc)) {
NEWPARENT->splitTop = true;
@@ -417,11 +422,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
}
} else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
if ((SIDEBYSIDE &&
VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / *PWIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x / 2.f,
NEWPARENT->position.y + NEWPARENT->size.y)) ||
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
(!SIDEBYSIDE &&
VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / *PWIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x,
NEWPARENT->position.y + NEWPARENT->size.y / 2.f))) {
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
// we are hovering over the first node, make PNODE first.
NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[0] = PNODE;
@@ -450,18 +453,14 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
}
// Update the children
if (!verticalOverride && (NEWPARENT->size.x * *PWIDTHMULTIPLIER > NEWPARENT->size.y || horizontalOverride)) {
if (!verticalOverride && (NEWPARENT->box.w * *PWIDTHMULTIPLIER > NEWPARENT->box.h || horizontalOverride)) {
// split left/right -> forced
OPENINGON->position = NEWPARENT->position;
OPENINGON->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y);
PNODE->position = Vector2D(NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y);
PNODE->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y);
OPENINGON->box = {NEWPARENT->box.pos(), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
PNODE->box = {Vector2D(NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
} else {
// split top/bottom
OPENINGON->position = NEWPARENT->position;
OPENINGON->size = Vector2D(NEWPARENT->size.x, NEWPARENT->size.y / 2.f);
PNODE->position = Vector2D(NEWPARENT->position.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f);
PNODE->size = Vector2D(NEWPARENT->size.x, NEWPARENT->size.y / 2.f);
OPENINGON->box = {NEWPARENT->box.pos(), Vector2D(NEWPARENT->box.w, NEWPARENT->box.h / 2.f)};
PNODE->box = {Vector2D(NEWPARENT->box.x, NEWPARENT->box.y + NEWPARENT->box.h / 2.f), Vector2D(NEWPARENT->box.w, NEWPARENT->box.h / 2.f)};
}
OPENINGON->pParent = NEWPARENT;
@@ -469,8 +468,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow) {
NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride);
applyNodeDataToWindow(PNODE);
applyNodeDataToWindow(OPENINGON);
recalculateMonitor(pWindow->m_iMonitorID);
pWindow->applyGroupRules();
}
void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
@@ -497,9 +497,8 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
const auto PSIBLING = PPARENT->children[0] == PNODE ? PPARENT->children[1] : PPARENT->children[0];
PSIBLING->position = PPARENT->position;
PSIBLING->size = PPARENT->size;
PSIBLING->pParent = PPARENT->pParent;
PSIBLING->box = PPARENT->box;
PSIBLING->pParent = PPARENT->pParent;
if (PPARENT->pParent != nullptr) {
if (PPARENT->pParent->children[0] == PPARENT) {
@@ -538,8 +537,7 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->specialWorkspaceID);
if (TOPNODE && PMONITOR) {
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
TOPNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
TOPNODE->recalcSizePosRecursive();
}
}
@@ -554,11 +552,11 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
} else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
SDwindleNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
fakeNode.workspaceID = PWORKSPACE->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.position;
PFULLWINDOW->m_vSize = fakeNode.size;
PFULLWINDOW->m_vPosition = fakeNode.box.pos();
PFULLWINDOW->m_vSize = fakeNode.box.size();
fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode);
}
@@ -569,8 +567,7 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace);
if (TOPNODE && PMONITOR) {
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
TOPNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
TOPNODE->recalcSizePosRecursive();
}
}
@@ -615,7 +612,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
m_PseudoDragFlags.started = true;
const auto pseudoSize = PWINDOW->m_vRealSize.goalv();
const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->position + ((PNODE->size / 2) - (pseudoSize / 2)));
const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->box.pos() + ((PNODE->box.size() / 2) - (pseudoSize / 2)));
if (mouseOffset.x > 0 && mouseOffset.x < pseudoSize.x && mouseOffset.y > 0 && mouseOffset.y < pseudoSize.y) {
m_PseudoDragFlags.pseudo = true;
@@ -638,8 +635,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
else
PWINDOW->m_vPseudoSize.y -= pixResize.y * 2;
PWINDOW->m_vPseudoSize.x = std::clamp(PWINDOW->m_vPseudoSize.x, 30.0, PNODE->size.x);
PWINDOW->m_vPseudoSize.y = std::clamp(PWINDOW->m_vPseudoSize.y, 30.0, PNODE->size.y);
PWINDOW->m_vPseudoSize.x = std::clamp(PWINDOW->m_vPseudoSize.x, 30.0, PNODE->box.w);
PWINDOW->m_vPseudoSize.y = std::clamp(PWINDOW->m_vPseudoSize.y, 30.0, PNODE->box.h);
PWINDOW->m_vLastFloatingSize = PWINDOW->m_vPseudoSize;
PNODE->recalcSizePosRecursive(*PANIMATE == 0);
@@ -686,30 +683,30 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
}
if (PHOUTER) {
PHOUTER->pParent->splitRatio = std::clamp(PHOUTER->pParent->splitRatio + allowedMovement.x * 2.f / PHOUTER->pParent->size.x, 0.1, 1.9);
PHOUTER->pParent->splitRatio = std::clamp(PHOUTER->pParent->splitRatio + allowedMovement.x * 2.f / PHOUTER->pParent->box.w, 0.1, 1.9);
if (PHINNER) {
const auto ORIGINAL = PHINNER->size.x;
const auto ORIGINAL = PHINNER->box.w;
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
if (PHINNER->pParent->children[0] == PHINNER)
PHINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.x) / PHINNER->pParent->size.x * 2.f, 0.1, 1.9);
PHINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9);
else
PHINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.x) / PHINNER->pParent->size.x * 2.f, 0.1, 1.9);
PHINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9);
PHINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
} else
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
}
if (PVOUTER) {
PVOUTER->pParent->splitRatio = std::clamp(PVOUTER->pParent->splitRatio + allowedMovement.y * 2.f / PVOUTER->pParent->size.y, 0.1, 1.9);
PVOUTER->pParent->splitRatio = std::clamp(PVOUTER->pParent->splitRatio + allowedMovement.y * 2.f / PVOUTER->pParent->box.h, 0.1, 1.9);
if (PVINNER) {
const auto ORIGINAL = PVINNER->size.y;
const auto ORIGINAL = PVINNER->box.h;
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
if (PVINNER->pParent->children[0] == PVINNER)
PVINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.y) / PVINNER->pParent->size.y * 2.f, 0.1, 1.9);
PVINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9);
else
PVINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.y) / PVINNER->pParent->size.y * 2.f, 0.1, 1.9);
PVINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9);
PVINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
} else
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
@@ -729,11 +726,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
// No parent means we have only 2 windows, and thus one axis of freedom
if (!PPARENT2) {
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
allowedMovement.x *= 2.f / PPARENT->box.w;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
allowedMovement.y *= 2.f / PPARENT->box.h;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
}
@@ -748,11 +745,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
// no parent, one axis of freedom
if (!PPARENT2) {
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
allowedMovement.x *= 2.f / PPARENT->box.w;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
allowedMovement.y *= 2.f / PPARENT->box.h;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
}
@@ -764,8 +761,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
const auto SIDECONTAINER = PARENTSIDEBYSIDE ? PPARENT : PPARENT2;
const auto TOPCONTAINER = PARENTSIDEBYSIDE ? PPARENT2 : PPARENT;
allowedMovement.x *= 2.f / SIDECONTAINER->size.x;
allowedMovement.y *= 2.f / TOPCONTAINER->size.y;
allowedMovement.x *= 2.f / SIDECONTAINER->box.w;
allowedMovement.y *= 2.f / TOPCONTAINER->box.h;
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, 0.1, 1.9);
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, 0.1, 1.9);
@@ -833,11 +830,10 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
SDwindleNodeData fakeNode;
fakeNode.pWindow = pWindow;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.position;
pWindow->m_vSize = fakeNode.size;
pWindow->m_vPosition = fakeNode.box.pos();
pWindow->m_vSize = fakeNode.box.size();
applyNodeDataToWindow(&fakeNode);
}
@@ -847,7 +843,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pCompositor->moveWindowToTop(pWindow);
g_pCompositor->changeWindowZOrder(pWindow, true);
recalculateMonitor(PMONITOR->ID);
}
@@ -882,6 +878,43 @@ SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(CWindow* pWindow
return hints;
}
void CHyprDwindleLayout::moveWindowTo(CWindow* pWindow, const std::string& dir) {
if (!isDirection(dir))
return;
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE)
return;
Vector2D focalPoint;
switch (dir[0]) {
case 't':
case 'u': focalPoint = pWindow->m_vPosition + Vector2D{pWindow->m_vSize.x / 2.f, -1}; break;
case 'd':
case 'b': focalPoint = pWindow->m_vPosition + Vector2D{pWindow->m_vSize.x / 2.f, pWindow->m_vSize.y + 1}; break;
case 'l': focalPoint = pWindow->m_vPosition + Vector2D{-1, pWindow->m_vSize.y / 2.f}; break;
case 'r': focalPoint = pWindow->m_vPosition + Vector2D{pWindow->m_vSize.x + 1, pWindow->m_vSize.y / 2.f}; break;
default: UNREACHABLE();
}
onWindowRemovedTiling(pWindow);
m_vOverrideFocalPoint = focalPoint;
const auto PMONITORFOCAL = g_pCompositor->getMonitorFromVector(focalPoint);
if (PMONITORFOCAL->ID != pWindow->m_iMonitorID) {
pWindow->moveToWorkspace(PMONITORFOCAL->activeWorkspace);
pWindow->m_iMonitorID = PMONITORFOCAL->ID;
}
onWindowCreatedTiling(pWindow);
m_vOverrideFocalPoint.reset();
}
void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
// windows should be valid, insallah
@@ -912,17 +945,15 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
}
if (ACTIVE1) {
ACTIVE1->position = PNODE->position;
ACTIVE1->size = PNODE->size;
ACTIVE1->pWindow->m_vPosition = ACTIVE1->position;
ACTIVE1->pWindow->m_vSize = ACTIVE1->size;
ACTIVE1->box = PNODE->box;
ACTIVE1->pWindow->m_vPosition = ACTIVE1->box.pos();
ACTIVE1->pWindow->m_vSize = ACTIVE1->box.size();
}
if (ACTIVE2) {
ACTIVE2->position = PNODE2->position;
ACTIVE2->size = PNODE2->size;
ACTIVE2->pWindow->m_vPosition = ACTIVE2->position;
ACTIVE2->pWindow->m_vSize = ACTIVE2->size;
ACTIVE2->box = PNODE2->box;
ACTIVE2->pWindow->m_vPosition = ACTIVE2->box.pos();
ACTIVE2->pWindow->m_vSize = ACTIVE2->box.size();
}
g_pHyprRenderer->damageWindow(pWindow);
@@ -958,26 +989,26 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str
switch (direction.front()) {
case 'u':
case 't': {
overrideDirection = OneTimeFocus::UP;
overrideDirection = DIRECTION_UP;
break;
}
case 'd':
case 'b': {
overrideDirection = OneTimeFocus::DOWN;
overrideDirection = DIRECTION_DOWN;
break;
}
case 'r': {
overrideDirection = OneTimeFocus::RIGHT;
overrideDirection = DIRECTION_RIGHT;
break;
}
case 'l': {
overrideDirection = OneTimeFocus::LEFT;
overrideDirection = DIRECTION_LEFT;
break;
}
default: {
// any other character resets the focus direction
// needed for the persistent mode
overrideDirection = OneTimeFocus::NOFOCUS;
overrideDirection = DIRECTION_DEFAULT;
break;
}
}

View File

@@ -1,21 +1,15 @@
#pragma once
#include "IHyprLayout.hpp"
#include <list>
#include <deque>
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include <array>
#include <optional>
#include <format>
class CHyprDwindleLayout;
enum eFullscreenMode : uint8_t;
enum OneTimeFocus {
UP = 0,
RIGHT,
DOWN,
LEFT,
NOFOCUS,
};
enum eFullscreenMode : int8_t;
struct SDwindleNodeData {
SDwindleNodeData* pParent = nullptr;
@@ -27,8 +21,7 @@ struct SDwindleNodeData {
bool splitTop = false; // for preserve_split
Vector2D position;
Vector2D size;
CBox box = {0};
int workspaceID = -1;
@@ -36,10 +29,12 @@ struct SDwindleNodeData {
bool valid = true;
bool ignoreFullscreenChecks = false;
// For list lookup
bool operator==(const SDwindleNodeData& rhs) const {
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 && box == rhs.box && pParent == rhs.pParent && children[0] == rhs.children[0] &&
children[1] == rhs.children[1];
}
void recalcSizePosRecursive(bool force = false, bool horizontalOverride = false, bool verticalOverride = false);
@@ -49,7 +44,7 @@ struct SDwindleNodeData {
class CHyprDwindleLayout : public IHyprLayout {
public:
virtual void onWindowCreatedTiling(CWindow*);
virtual void onWindowCreatedTiling(CWindow*, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowRemovedTiling(CWindow*);
virtual bool isWindowTiled(CWindow*);
virtual void recalculateMonitor(const int&);
@@ -60,6 +55,7 @@ class CHyprDwindleLayout : public IHyprLayout {
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
virtual void switchWindows(CWindow*, CWindow*);
virtual void moveWindowTo(CWindow*, const std::string& dir);
virtual void alterSplitRatio(CWindow*, float, bool);
virtual std::string getLayoutName();
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
@@ -77,15 +73,31 @@ class CHyprDwindleLayout : public IHyprLayout {
bool yExtent = false;
} m_PseudoDragFlags;
int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
SDwindleNodeData* getNodeFromWindow(CWindow*);
SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
SDwindleNodeData* getMasterNodeOnWorkspace(const int&);
std::optional<Vector2D> m_vOverrideFocalPoint; // for onWindowCreatedTiling.
void toggleSplit(CWindow*);
int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
SDwindleNodeData* getNodeFromWindow(CWindow*);
SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
SDwindleNodeData* getMasterNodeOnWorkspace(const int&);
OneTimeFocus overrideDirection = OneTimeFocus::NOFOCUS;
void toggleSplit(CWindow*);
eDirection overrideDirection = DIRECTION_DEFAULT;
friend struct SDwindleNodeData;
};
template <typename CharT>
struct std::formatter<SDwindleNodeData*, CharT> : std::formatter<CharT> {
template <typename FormatContext>
auto format(const SDwindleNodeData* const& node, FormatContext& ctx) const {
auto out = ctx.out();
if (!node)
return std::format_to(out, "[Node nullptr]");
std::format_to(out, "[Node {:x}: workspace: {}, pos: {:j2}, size: {:j2}", (uintptr_t)node, node->workspaceID, node->box.pos(), node->box.size());
if (!node->isNode && node->pWindow)
std::format_to(out, ", window: {:x}", node->pWindow);
return std::format_to(out, "]");
}
};

View File

@@ -1,12 +1,13 @@
#include "IHyprLayout.hpp"
#include "../defines.hpp"
#include "../Compositor.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
void IHyprLayout::onWindowCreated(CWindow* pWindow) {
void IHyprLayout::onWindowCreated(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) {
onWindowCreatedFloating(pWindow);
} else {
wlr_box desiredGeometry = {0};
CBox desiredGeometry = {};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
@@ -18,7 +19,7 @@ void IHyprLayout::onWindowCreated(CWindow* pWindow) {
pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize;
onWindowCreatedTiling(pWindow);
onWindowCreatedTiling(pWindow, direction);
}
}
@@ -31,24 +32,19 @@ void IHyprLayout::onWindowRemoved(CWindow* pWindow) {
pWindow->m_sGroupData.pNextWindow = nullptr;
else {
// find last window and update
CWindow* curr = pWindow;
const auto CURRWASVISIBLE = curr->getGroupCurrent() == curr;
CWindow* PWINDOWPREV = pWindow->getGroupPrevious();
const auto WINDOWISVISIBLE = pWindow->getGroupCurrent() == pWindow;
while (curr->m_sGroupData.pNextWindow != pWindow)
curr = curr->m_sGroupData.pNextWindow;
if (WINDOWISVISIBLE)
PWINDOWPREV->setGroupCurrent(PWINDOWPREV);
if (CURRWASVISIBLE)
curr->setGroupCurrent(curr);
curr->m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow;
PWINDOWPREV->m_sGroupData.pNextWindow = pWindow->m_sGroupData.pNextWindow;
pWindow->m_sGroupData.pNextWindow = nullptr;
if (pWindow->m_sGroupData.head) {
pWindow->m_sGroupData.head = false;
curr->m_sGroupData.head = true;
curr->m_sGroupData.locked = pWindow->m_sGroupData.locked;
pWindow->m_sGroupData.locked = false;
std::swap(PWINDOWPREV->m_sGroupData.head, pWindow->m_sGroupData.head);
std::swap(PWINDOWPREV->m_sGroupData.locked, pWindow->m_sGroupData.locked);
}
if (pWindow == m_pLastTiledWindow)
@@ -56,6 +52,10 @@ void IHyprLayout::onWindowRemoved(CWindow* pWindow) {
pWindow->setHidden(false);
pWindow->updateWindowDecos();
PWINDOWPREV->getGroupCurrent()->updateWindowDecos();
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
return;
}
}
@@ -76,7 +76,7 @@ void IHyprLayout::onWindowRemovedFloating(CWindow* pWindow) {
void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
wlr_box desiredGeometry = {0};
CBox desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -90,7 +90,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
if (!PMONITOR) {
Debug::log(ERR, "Window %lx (%s) has an invalid monitor in onWindowCreatedFloating!!!", pWindow, pWindow->m_szTitle.c_str());
Debug::log(ERR, "{:m} has an invalid monitor in onWindowCreatedFloating!!!", pWindow);
return;
}
@@ -137,7 +137,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
}
// TODO: detect a popup in a more consistent way.
if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible) {
if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible || !pWindow->m_bIsX11) {
// 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);
} else {
@@ -162,7 +162,10 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
if (pWindow->m_iX11Type != 2) {
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pCompositor->moveWindowToTop(pWindow);
g_pCompositor->changeWindowZOrder(pWindow, true);
} else {
pWindow->m_vPendingReportedSize = pWindow->m_vRealSize.goalv();
pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize;
}
}
@@ -238,7 +241,7 @@ void IHyprLayout::onBeginDragWindow() {
g_pKeybindManager->shadowKeybinds();
g_pCompositor->focusWindow(DRAGGINGWINDOW);
g_pCompositor->moveWindowToTop(DRAGGINGWINDOW);
g_pCompositor->changeWindowZOrder(DRAGGINGWINDOW, true);
}
void IHyprLayout::onEndDragWindow() {
@@ -255,17 +258,46 @@ void IHyprLayout::onEndDragWindow() {
g_pInputManager->unsetCursorImage();
g_pInputManager->currentlyDraggedWindow = nullptr;
g_pInputManager->m_bWasDraggingWindow = true;
if (DRAGGINGWINDOW->m_bDraggingTiled) {
DRAGGINGWINDOW->m_bIsFloating = false;
g_pInputManager->refocus();
changeWindowFloatingMode(DRAGGINGWINDOW);
DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize;
} else if (g_pInputManager->dragMode == MBIND_MOVE) {
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS, DRAGGINGWINDOW);
if (pWindow && pWindow->m_bIsFloating) {
for (auto& wd : pWindow->m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
if (!wd->onEndWindowDragOnDeco(DRAGGINGWINDOW, MOUSECOORDS))
return;
break;
}
}
if (pWindow->m_sGroupData.pNextWindow && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) {
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
(*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
pWindow->setGroupCurrent(DRAGGINGWINDOW);
DRAGGINGWINDOW->updateWindowDecos();
if (!DRAGGINGWINDOW->getDecorationByType(DECORATION_GROUPBAR))
DRAGGINGWINDOW->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(DRAGGINGWINDOW));
}
}
}
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
g_pCompositor->focusWindow(DRAGGINGWINDOW);
g_pInputManager->m_bWasDraggingWindow = false;
}
void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
@@ -302,11 +334,13 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (g_pInputManager->dragMode == MBIND_MOVE) {
if (*PANIMATEMOUSE) {
DRAGGINGWINDOW->m_vRealPosition = m_vBeginDragPositionXY + DELTA;
} else {
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA);
}
CBox wb = {m_vBeginDragPositionXY + DELTA, DRAGGINGWINDOW->m_vRealSize.goalv()};
wb.round();
if (*PANIMATEMOUSE)
DRAGGINGWINDOW->m_vRealPosition = wb.pos();
else
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos());
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
} else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) {
@@ -358,12 +392,15 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT)
newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0);
CBox wb = {newPos, newSize};
wb.round();
if (*PANIMATE) {
DRAGGINGWINDOW->m_vRealSize = newSize;
DRAGGINGWINDOW->m_vRealPosition = newPos;
DRAGGINGWINDOW->m_vRealSize = wb.size();
DRAGGINGWINDOW->m_vRealPosition = wb.pos();
} else {
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(newSize);
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(newPos);
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(wb.size());
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos());
}
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
@@ -403,13 +440,13 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
const auto TILED = isWindowTiled(pWindow);
// event
g_pEventManager->postEvent(SHyprIPCEvent{"changefloatingmode", getFormat("%lx,%d", pWindow, (int)TILED)});
g_pEventManager->postEvent(SHyprIPCEvent{"changefloatingmode", std::format("{:x},{}", (uintptr_t)pWindow, (int)TILED)});
EMIT_HOOK_EVENT("changeFloatingMode", pWindow);
if (!TILED) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID;
pWindow->moveToWorkspace(PNEWMON->activeWorkspace);
pWindow->moveToWorkspace(PNEWMON->specialWorkspaceID != 0 ? PNEWMON->specialWorkspaceID : PNEWMON->activeWorkspace);
pWindow->updateGroupOutputs();
// save real pos cuz the func applies the default 5,5 mid
@@ -417,7 +454,8 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
const auto PSAVEDSIZE = pWindow->m_vRealSize.goalv();
// if the window is pseudo, update its size
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv();
if (!pWindow->m_bDraggingTiled)
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
@@ -437,7 +475,7 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
} else {
onWindowRemovedTiling(pWindow);
g_pCompositor->moveWindowToTop(pWindow);
g_pCompositor->changeWindowZOrder(pWindow, true);
if (DELTALESSTHAN(pWindow->m_vRealSize.vec().x, pWindow->m_vLastFloatingSize.x, 10) && DELTALESSTHAN(pWindow->m_vRealSize.vec().y, pWindow->m_vLastFloatingSize.y, 10)) {
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f + Vector2D{10, 10};
@@ -512,8 +550,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
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 && PWINDOWCANDIDATE != pWindow)
if (const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(pWindow->middle()); PWINDOWCANDIDATE && PWINDOWCANDIDATE != pWindow)
return PWINDOWCANDIDATE;
// if not, floating window
@@ -528,7 +565,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
}
// 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);
const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(pWindow->middle());
if (!PWINDOWCANDIDATE || pWindow == PWINDOWCANDIDATE || !PWINDOWCANDIDATE->m_bIsMapped || PWINDOWCANDIDATE->isHidden() || PWINDOWCANDIDATE->m_bX11ShouldntFocus ||
PWINDOWCANDIDATE->m_iX11Type == 2 || PWINDOWCANDIDATE->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
@@ -537,12 +574,22 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
return PWINDOWCANDIDATE;
}
void IHyprLayout::requestFocusForWindow(CWindow* pWindow) {
bool IHyprLayout::isWindowReachable(CWindow* pWindow) {
return pWindow && (!pWindow->isHidden() || pWindow->m_sGroupData.pNextWindow);
}
void IHyprLayout::bringWindowToTop(CWindow* pWindow) {
if (pWindow == nullptr)
return;
if (pWindow->isHidden() && pWindow->m_sGroupData.pNextWindow) {
// grouped, change the current to this window
pWindow->setGroupCurrent(pWindow);
}
}
void IHyprLayout::requestFocusForWindow(CWindow* pWindow) {
bringWindowToTop(pWindow);
g_pCompositor->focusWindow(pWindow);
}

View File

@@ -13,9 +13,10 @@ struct SLayoutMessageHeader {
CWindow* pWindow = nullptr;
};
enum eFullscreenMode : uint8_t;
enum eFullscreenMode : int8_t;
enum eRectCorner {
enum eRectCorner
{
CORNER_NONE = 0,
CORNER_TOPLEFT,
CORNER_TOPRIGHT,
@@ -23,6 +24,15 @@ enum eRectCorner {
CORNER_BOTTOMLEFT
};
enum eDirection
{
DIRECTION_DEFAULT = -1,
DIRECTION_UP = 0,
DIRECTION_RIGHT,
DIRECTION_DOWN,
DIRECTION_LEFT
};
class IHyprLayout {
public:
virtual ~IHyprLayout() = 0;
@@ -34,8 +44,8 @@ class IHyprLayout {
The layout HAS TO set the goal pos and size (anim mgr will use it)
If !animationinprogress, then the anim mgr will not apply an anim.
*/
virtual void onWindowCreated(CWindow*);
virtual void onWindowCreatedTiling(CWindow*) = 0;
virtual void onWindowCreated(CWindow*, eDirection direction = DIRECTION_DEFAULT);
virtual void onWindowCreatedTiling(CWindow*, eDirection direction = DIRECTION_DEFAULT) = 0;
virtual void onWindowCreatedFloating(CWindow*);
/*
@@ -122,6 +132,12 @@ class IHyprLayout {
*/
virtual void switchWindows(CWindow*, CWindow*) = 0;
/*
Called when the user requests a window move in a direction.
The layout is free to ignore.
*/
virtual void moveWindowTo(CWindow*, const std::string& direction) = 0;
/*
Called when the user requests to change the splitratio by or to X
on a window
@@ -148,10 +164,22 @@ class IHyprLayout {
*/
virtual void replaceWindowDataWith(CWindow* from, CWindow* to) = 0;
/*
Determines if a window can be focused. If hidden this usually means the window is part of a group.
*/
virtual bool isWindowReachable(CWindow*);
/*
Called before an attempt is made to focus a window.
Brings the window to the top of any groups and ensures it is not hidden.
If the window is unmapped following this call, the focus attempt will fail.
*/
virtual void bringWindowToTop(CWindow*);
/*
Called via the foreign toplevel activation protocol.
Focuses a window, bringing it to the top of its group if applicable.
May be ignored.
May be ignored.
*/
virtual void requestFocusForWindow(CWindow*);

View File

@@ -1,5 +1,6 @@
#include "MasterLayout.hpp"
#include "../Compositor.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include <ranges>
SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(CWindow* pWindow) {
@@ -41,13 +42,21 @@ SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) {
const auto PWORKSPACEDATA = &m_lMasterWorkspacesData.emplace_back();
PWORKSPACEDATA->workspaceID = ws;
const auto orientation = &g_pConfigManager->getConfigValuePtr("master:orientation")->strValue;
if (*orientation == "top") {
const auto layoutoptsForWs = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(ws)).layoutopts;
auto orientationForWs = *orientation;
try {
if (layoutoptsForWs.contains("orientation"))
orientationForWs = std::any_cast<std::string>(layoutoptsForWs.at("orientation"));
} catch (std::exception& e) { Debug::log(ERR, "Error from layoutopt rules: {}", e.what()); }
if (orientationForWs == "top") {
PWORKSPACEDATA->orientation = ORIENTATION_TOP;
} else if (*orientation == "right") {
} else if (orientationForWs == "right") {
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
} else if (*orientation == "bottom") {
} else if (orientationForWs == "bottom") {
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
} else if (*orientation == "left") {
} else if (orientationForWs == "left") {
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
} else {
PWORKSPACEDATA->orientation = ORIENTATION_CENTER;
@@ -68,7 +77,7 @@ SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const int& ws) {
return nullptr;
}
void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating)
return;
@@ -91,37 +100,108 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
getNodeFromWindow(g_pCompositor->m_pLastWindow) :
getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID);
// if it's a group, add the window
if (OPENINGON && OPENINGON->pWindow->m_sGroupData.pNextWindow && !OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked && !g_pKeybindManager->m_bGroupsLocked &&
OPENINGON != PNODE) { // target is an unlocked group
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
if (!pWindow->m_sGroupData.pNextWindow) { // source is not a group
m_lMasterNodesData.remove(*PNODE);
OPENINGON->pWindow->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
if (g_pInputManager->m_bWasDraggingWindow && OPENINGON) {
for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
g_pCompositor->focusWindow(pWindow);
return;
}
if (!pWindow->getGroupHead()->m_sGroupData.locked) { // source is an unlocked group
m_lMasterNodesData.remove(*PNODE);
OPENINGON->pWindow->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
g_pCompositor->focusWindow(pWindow);
return;
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS))
return;
break;
}
}
}
if (*PNEWISMASTER || WINDOWSONWORKSPACE == 1 || (!pWindow->m_bFirstMap && OPENINGON->isMaster)) {
// if it's a group, add the window
if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow)) {
m_lMasterNodesData.remove(*PNODE);
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return;
}
pWindow->applyGroupRules();
static auto* const PDROPATCURSOR = &g_pConfigManager->getConfigValuePtr("master:drop_at_cursor")->intValue;
const auto PWORKSPACEDATA = getMasterWorkspaceData(pWindow->m_iWorkspaceID);
eOrientation orientation = PWORKSPACEDATA->orientation;
const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE);
bool forceDropAsMaster = false;
// if dragging window to move, drop it at the cursor position instead of bottom/top of stack
if (*PDROPATCURSOR && g_pInputManager->dragMode == MBIND_MOVE) {
if (WINDOWSONWORKSPACE > 2) {
for (auto it = m_lMasterNodesData.begin(); it != m_lMasterNodesData.end(); ++it) {
if (it->workspaceID != pWindow->m_iWorkspaceID)
continue;
const CBox box = it->pWindow->getWindowIdealBoundingBoxIgnoreReserved();
if (box.containsPoint(MOUSECOORDS)) {
switch (orientation) {
case ORIENTATION_LEFT:
case ORIENTATION_RIGHT:
if (MOUSECOORDS.y > it->pWindow->middle().y)
++it;
break;
case ORIENTATION_TOP:
case ORIENTATION_BOTTOM:
if (MOUSECOORDS.x > it->pWindow->middle().x)
++it;
break;
case ORIENTATION_CENTER: break;
default: UNREACHABLE();
}
m_lMasterNodesData.splice(it, m_lMasterNodesData, NODEIT);
break;
}
}
} else if (WINDOWSONWORKSPACE == 2) {
// when dropping as the second tiled window in the workspace,
// make it the master only if the cursor is on the master side of the screen
for (auto& nd : m_lMasterNodesData) {
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
switch (orientation) {
case ORIENTATION_LEFT:
case ORIENTATION_CENTER:
if (MOUSECOORDS.x < nd.pWindow->middle().x)
forceDropAsMaster = true;
break;
case ORIENTATION_RIGHT:
if (MOUSECOORDS.x > nd.pWindow->middle().x)
forceDropAsMaster = true;
break;
case ORIENTATION_TOP:
if (MOUSECOORDS.y < nd.pWindow->middle().y)
forceDropAsMaster = true;
break;
case ORIENTATION_BOTTOM:
if (MOUSECOORDS.y > nd.pWindow->middle().y)
forceDropAsMaster = true;
break;
default: UNREACHABLE();
}
break;
}
}
}
}
if ((*PNEWISMASTER && g_pInputManager->dragMode != MBIND_MOVE) || WINDOWSONWORKSPACE == 1 || (WINDOWSONWORKSPACE > 2 && !pWindow->m_bFirstMap && OPENINGON->isMaster) ||
forceDropAsMaster) {
for (auto& nd : m_lMasterNodesData) {
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
nd.isMaster = false;
@@ -156,13 +236,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow) {
}
}
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
recalculateMonitor(pWindow->m_iMonitorID);
}
@@ -266,8 +339,8 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
return;
const auto PWORKSPACEDATA = getMasterWorkspaceData(ws);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PMASTERNODE = getMasterNodeOnWorkspace(PWORKSPACE->m_iID);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PMASTERNODE = getMasterNodeOnWorkspace(PWORKSPACE->m_iID);
if (!PMASTERNODE)
return;
@@ -275,12 +348,13 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
eOrientation orientation = PWORKSPACEDATA->orientation;
bool centerMasterWindow = false;
static auto* const ALWAYSCENTER = &g_pConfigManager->getConfigValuePtr("master:always_center_master")->intValue;
static auto* const PSMARTRESIZING = &g_pConfigManager->getConfigValuePtr("master:smart_resizing")->intValue;
const auto MASTERS = getMastersOnWorkspace(PWORKSPACE->m_iID);
const auto WINDOWS = getNodesOnWorkspace(PWORKSPACE->m_iID);
const auto STACKWINDOWS = WINDOWS - MASTERS;
const auto WSSIZE = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
const auto WSPOS = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
const auto MASTERS = getMastersOnWorkspace(PWORKSPACE->m_iID);
const auto WINDOWS = getNodesOnWorkspace(PWORKSPACE->m_iID);
const auto STACKWINDOWS = WINDOWS - MASTERS;
const auto WSSIZE = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
const auto WSPOS = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
if (orientation == ORIENTATION_CENTER) {
if (STACKWINDOWS >= 2 || (*ALWAYSCENTER == 1)) {
@@ -290,6 +364,25 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
}
}
const float totalSize = (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) ? WSSIZE.x : WSSIZE.y;
const float masterAverageSize = totalSize / MASTERS;
const float slaveAverageSize = totalSize / STACKWINDOWS;
float masterAccumulatedSize = 0;
float slaveAccumulatedSize = 0;
if (*PSMARTRESIZING) {
// check the total width and height so that later
// if larger/smaller than screen size them down/up
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID == PWORKSPACE->m_iID) {
if (nd.isMaster)
masterAccumulatedSize += totalSize / MASTERS * nd.percSize;
else
slaveAccumulatedSize += totalSize / STACKWINDOWS * nd.percSize;
}
}
}
// compute placement of master window(s)
if (WINDOWS == 1 && !centerMasterWindow) {
PMASTERNODE->size = WSSIZE;
@@ -304,18 +397,23 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
float nextX = 0;
float nextY = 0;
if (orientation == ORIENTATION_BOTTOM)
nextY = WSSIZE.y - HEIGHT;
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || !nd.isMaster)
continue;
if (orientation == ORIENTATION_BOTTOM)
nextY = WSSIZE.y - HEIGHT;
float WIDTH = mastersLeft > 1 ? widthLeft / mastersLeft * nd.percSize : widthLeft;
if (WIDTH > widthLeft * 0.9f && mastersLeft > 1)
WIDTH = widthLeft * 0.9f;
nd.size = Vector2D(WIDTH, HEIGHT);
if (*PSMARTRESIZING) {
nd.percSize *= WSSIZE.x / masterAccumulatedSize;
WIDTH = masterAverageSize * nd.percSize;
}
nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
@@ -324,11 +422,11 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
nextX += WIDTH;
}
} else { // orientation left, right or center
float WIDTH = WSSIZE.x;
float heightLeft = WSSIZE.y;
int mastersLeft = MASTERS;
float nextX = 0;
float nextY = 0;
float WIDTH = WSSIZE.x;
float heightLeft = WSSIZE.y;
int mastersLeft = MASTERS;
float nextX = 0;
float nextY = 0;
if (STACKWINDOWS > 0 || centerMasterWindow)
WIDTH *= PMASTERNODE->percMaster;
@@ -347,7 +445,12 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (HEIGHT > heightLeft * 0.9f && mastersLeft > 1)
HEIGHT = heightLeft * 0.9f;
nd.size = Vector2D(WIDTH, HEIGHT);
if (*PSMARTRESIZING) {
nd.percSize *= WSSIZE.y / masterAccumulatedSize;
HEIGHT = masterAverageSize * nd.percSize;
}
nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
@@ -379,7 +482,12 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (WIDTH > widthLeft * 0.9f && slavesLeft > 1)
WIDTH = widthLeft * 0.9f;
nd.size = Vector2D(WIDTH, HEIGHT);
if (*PSMARTRESIZING) {
nd.percSize *= WSSIZE.x / slaveAccumulatedSize;
WIDTH = slaveAverageSize * nd.percSize;
}
nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
@@ -404,7 +512,12 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (HEIGHT > heightLeft * 0.9f && slavesLeft > 1)
HEIGHT = heightLeft * 0.9f;
nd.size = Vector2D(WIDTH, HEIGHT);
if (*PSMARTRESIZING) {
nd.percSize *= WSSIZE.y / slaveAccumulatedSize;
HEIGHT = slaveAverageSize * nd.percSize;
}
nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
@@ -426,18 +539,37 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
int slavesLeftR = 1 + (slavesLeft - 1) / 2;
int slavesLeftL = slavesLeft - slavesLeftR;
const float slaveAverageHeightL = WSSIZE.y / slavesLeftL;
const float slaveAverageHeightR = WSSIZE.y / slavesLeftR;
float slaveAccumulatedHeightL = 0;
float slaveAccumulatedHeightR = 0;
if (*PSMARTRESIZING) {
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster)
continue;
if (onRight) {
slaveAccumulatedHeightR += slaveAverageHeightR * nd.percSize;
} else {
slaveAccumulatedHeightL += slaveAverageHeightL * nd.percSize;
}
onRight = !onRight;
}
onRight = true;
}
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster)
continue;
if (onRight) {
nextX = WIDTH + PMASTERNODE->size.x;
nextY = nextYR;
nextX = WIDTH + PMASTERNODE->size.x;
nextY = nextYR;
heightLeft = heightLeftR;
slavesLeft = slavesLeftR;
} else {
nextX = 0;
nextY = nextYL;
nextX = 0;
nextY = nextYL;
heightLeft = heightLeftL;
slavesLeft = slavesLeftL;
}
@@ -446,7 +578,17 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
if (HEIGHT > heightLeft * 0.9f && slavesLeft > 1)
HEIGHT = heightLeft * 0.9f;
nd.size = Vector2D(WIDTH, HEIGHT);
if (*PSMARTRESIZING) {
if (onRight) {
nd.percSize *= WSSIZE.y / slaveAccumulatedHeightR;
HEIGHT = slaveAverageHeightR * nd.percSize;
} else {
nd.percSize *= WSSIZE.y / slaveAccumulatedHeightL;
HEIGHT = slaveAverageHeightL * nd.percSize;
}
}
nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
@@ -480,7 +622,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
}
if (!PMONITOR) {
Debug::log(ERR, "Orphaned Node %lx (workspace ID: %i)!!", pNode, pNode->workspaceID);
Debug::log(ERR, "Orphaned Node {}!!", pNode);
return;
}
@@ -495,17 +637,21 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
// if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID));
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return;
PWINDOW->updateSpecialRenderData();
static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
static auto* const PGAPSOUT = &g_pConfigManager->getConfigValuePtr("general:gaps_out")->intValue;
static auto* const PNOGAPSWHENONLY = &g_pConfigManager->getConfigValuePtr("master:no_gaps_when_only")->intValue;
static auto* const PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
if (!g_pCompositor->windowValidMapped(PWINDOW)) {
Debug::log(ERR, "Node %lx holding invalid window %lx!!", pNode, PWINDOW);
Debug::log(ERR, "Node {} holding invalid {}!!", pNode, PWINDOW);
return;
}
@@ -530,6 +676,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->updateWindowDecos();
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
return;
}
@@ -552,18 +700,24 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue;
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
PWINDOW->m_vRealSize = calcSize * *PSCALEFACTOR;
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
wb.round(); // avoid rounding mess
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize * *PSCALEFACTOR);
PWINDOW->m_vRealPosition = wb.pos();
PWINDOW->m_vRealSize = wb.size();
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
} else {
PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos;
CBox wb = {calcPos, calcSize};
wb.round(); // avoid rounding mess
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
PWINDOW->m_vRealPosition = wb.pos();
PWINDOW->m_vRealSize = wb.size();
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
}
if (m_bForceWarps) {
if (m_bForceWarps && !*PANIMATE) {
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vRealPosition.warp();
@@ -593,13 +747,27 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
return;
}
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PMONITOR->activeWorkspace);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PMONITOR->activeWorkspace);
static auto* const ALWAYSCENTER = &g_pConfigManager->getConfigValuePtr("master:always_center_master")->intValue;
static auto* const PSMARTRESIZING = &g_pConfigManager->getConfigValuePtr("master:smart_resizing")->intValue;
eOrientation orientation = PWORKSPACEDATA->orientation;
bool centered = orientation == ORIENTATION_CENTER && (*ALWAYSCENTER == 1);
double delta = 0;
eOrientation orientation = PWORKSPACEDATA->orientation;
bool centered = orientation == ORIENTATION_CENTER && (*ALWAYSCENTER == 1);
double delta = 0;
const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_vPosition.y + PWINDOW->m_vSize.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const bool DISPLAYRIGHT = STICKS(PWINDOW->m_vPosition.x + PWINDOW->m_vSize.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(PWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool LEFT = corner == CORNER_TOPLEFT || corner == CORNER_BOTTOMLEFT;
const bool TOP = corner == CORNER_TOPLEFT || corner == CORNER_TOPRIGHT;
const bool NONE = corner == CORNER_NONE;
const auto MASTERS = getMastersOnWorkspace(PNODE->workspaceID);
const auto WINDOWS = getNodesOnWorkspace(PNODE->workspaceID);
const auto STACKWINDOWS = WINDOWS - MASTERS;
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 && !centered)
return;
@@ -611,30 +779,95 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
case ORIENTATION_RIGHT: delta = -pixResize.x / PMONITOR->vecSize.x; break;
case ORIENTATION_BOTTOM: delta = -pixResize.y / PMONITOR->vecSize.y; break;
case ORIENTATION_TOP: delta = pixResize.y / PMONITOR->vecSize.y; break;
case ORIENTATION_CENTER: delta = pixResize.x / PMONITOR->vecSize.x; break;
case ORIENTATION_CENTER:
delta = pixResize.x / PMONITOR->vecSize.x;
if (WINDOWS > 2) {
if (!NONE || !PNODE->isMaster)
delta *= 2;
if ((!PNODE->isMaster && DISPLAYLEFT) || (PNODE->isMaster && LEFT && *PSMARTRESIZING))
delta = -delta;
}
break;
default: UNREACHABLE();
}
const auto workspaceIdForResizing = PMONITOR->specialWorkspaceID == 0 ? PMONITOR->activeWorkspace : PMONITOR->specialWorkspaceID;
for (auto& n : m_lMasterNodesData) {
if (n.isMaster && n.workspaceID == PMONITOR->activeWorkspace)
if (n.isMaster && n.workspaceID == workspaceIdForResizing)
n.percMaster = std::clamp(n.percMaster + delta, 0.05, 0.95);
}
// check the up/down resize
const auto RESIZEDELTA = PWORKSPACEDATA->orientation % 2 == 1 ? pixResize.x : pixResize.y;
const bool isStackVertical = orientation == ORIENTATION_LEFT || orientation == ORIENTATION_RIGHT || orientation == ORIENTATION_CENTER;
if (RESIZEDELTA != 0) {
if (PNODE->isMaster && getMastersOnWorkspace(PNODE->workspaceID) > 1) {
// check master size
const auto SIZE = PWORKSPACEDATA->orientation % 2 == 1 ?
(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) / getMastersOnWorkspace(PNODE->workspaceID) :
(PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / getMastersOnWorkspace(PNODE->workspaceID);
PNODE->percSize = std::clamp(PNODE->percSize + RESIZEDELTA / SIZE, 0.05, 1.95);
} else if (!PNODE->isMaster && (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) - getMastersOnWorkspace(PNODE->workspaceID)) > 1) {
const auto SIZE = PWORKSPACEDATA->orientation % 2 == 1 ?
(PMONITOR->vecSize.x - PMONITOR->vecReservedTopLeft.x - PMONITOR->vecReservedBottomRight.x) / (getNodesOnWorkspace(PNODE->workspaceID) - getMastersOnWorkspace(PNODE->workspaceID)) :
(PMONITOR->vecSize.y - PMONITOR->vecReservedTopLeft.y - PMONITOR->vecReservedBottomRight.y) / (getNodesOnWorkspace(PNODE->workspaceID) - getMastersOnWorkspace(PNODE->workspaceID));
const auto RESIZEDELTA = isStackVertical ? pixResize.y : pixResize.x;
const auto WSSIZE = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
auto nodesInSameColumn = PNODE->isMaster ? MASTERS : STACKWINDOWS;
if (orientation == ORIENTATION_CENTER && !PNODE->isMaster)
nodesInSameColumn = DISPLAYRIGHT ? (nodesInSameColumn + 1) / 2 : nodesInSameColumn / 2;
const auto SIZE = isStackVertical ? WSSIZE.y / nodesInSameColumn : WSSIZE.x / nodesInSameColumn;
if (RESIZEDELTA != 0 && nodesInSameColumn > 1) {
if (!*PSMARTRESIZING) {
PNODE->percSize = std::clamp(PNODE->percSize + RESIZEDELTA / SIZE, 0.05, 1.95);
} else {
const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE);
const auto REVNODEIT = std::find(m_lMasterNodesData.rbegin(), m_lMasterNodesData.rend(), *PNODE);
const float totalSize = isStackVertical ? WSSIZE.y : WSSIZE.x;
const float minSize = totalSize / nodesInSameColumn * 0.2;
const bool resizePrevNodes = isStackVertical ? (TOP || DISPLAYBOTTOM) && !DISPLAYTOP : (LEFT || DISPLAYRIGHT) && !DISPLAYLEFT;
int nodesLeft = 0;
float sizeLeft = 0;
int nodeCount = 0;
// check the sizes of all the nodes to be resized for later calculation
auto checkNodesLeft = [&sizeLeft, &nodesLeft, orientation, isStackVertical, &nodeCount, PNODE](auto it) {
if (it.isMaster != PNODE->isMaster || it.workspaceID != PNODE->workspaceID)
return;
nodeCount++;
if (!it.isMaster && orientation == ORIENTATION_CENTER && nodeCount % 2 == 1)
return;
sizeLeft += isStackVertical ? it.size.y : it.size.x;
nodesLeft++;
};
float resizeDiff;
if (resizePrevNodes) {
std::for_each(std::next(REVNODEIT), m_lMasterNodesData.rend(), checkNodesLeft);
resizeDiff = -RESIZEDELTA;
} else {
std::for_each(std::next(NODEIT), m_lMasterNodesData.end(), checkNodesLeft);
resizeDiff = RESIZEDELTA;
}
const float nodeSize = isStackVertical ? PNODE->size.y : PNODE->size.x;
const float maxSizeIncrease = sizeLeft - nodesLeft * minSize;
const float maxSizeDecrease = minSize - nodeSize;
// leaves enough room for the other nodes
resizeDiff = std::clamp(resizeDiff, maxSizeDecrease, maxSizeIncrease);
PNODE->percSize += resizeDiff / SIZE;
// resize the other nodes
nodeCount = 0;
auto resizeNodesLeft = [maxSizeIncrease, resizeDiff, minSize, orientation, isStackVertical, SIZE, &nodeCount, nodesLeft, PNODE](auto& it) {
if (it.isMaster != PNODE->isMaster || it.workspaceID != PNODE->workspaceID)
return;
nodeCount++;
// if center orientation, only resize when on the same side
if (!it.isMaster && orientation == ORIENTATION_CENTER && nodeCount % 2 == 1)
return;
const float size = isStackVertical ? it.size.y : it.size.x;
const float resizeDeltaForEach = maxSizeIncrease != 0 ? resizeDiff * (size - minSize) / maxSizeIncrease : resizeDiff / nodesLeft;
it.percSize -= resizeDeltaForEach / SIZE;
};
if (resizePrevNodes) {
std::for_each(std::next(REVNODEIT), m_lMasterNodesData.rend(), resizeNodesLeft);
} else {
std::for_each(std::next(NODEIT), m_lMasterNodesData.end(), resizeNodesLeft);
}
}
}
@@ -701,12 +934,13 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
// To keep consistent with the settings without C+P code
SMasterNodeData fakeNode;
fakeNode.pWindow = pWindow;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.position;
pWindow->m_vSize = fakeNode.size;
fakeNode.pWindow = pWindow;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.position;
pWindow->m_vSize = fakeNode.size;
fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode);
}
@@ -716,7 +950,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pCompositor->moveWindowToTop(pWindow);
g_pCompositor->changeWindowZOrder(pWindow, true);
recalculateMonitor(PMONITOR->ID);
}
@@ -738,6 +972,24 @@ SWindowRenderLayoutHints CHyprMasterLayout::requestRenderHints(CWindow* pWindow)
return hints; // master doesnt have any hints
}
void CHyprMasterLayout::moveWindowTo(CWindow* pWindow, const std::string& dir) {
if (!isDirection(dir))
return;
const auto PWINDOW2 = g_pCompositor->getWindowInDirection(pWindow, dir[0]);
if (pWindow->m_iWorkspaceID != PWINDOW2->m_iWorkspaceID) {
// if different monitors, send to monitor
onWindowRemovedTiling(pWindow);
pWindow->moveToWorkspace(PWINDOW2->m_iWorkspaceID);
pWindow->m_iMonitorID = PWINDOW2->m_iMonitorID;
onWindowCreatedTiling(pWindow);
} else {
// if same monitor, switch windows
switchWindows(pWindow, PWINDOW2);
}
}
void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
// windows should be valid, insallah
@@ -834,7 +1086,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
return;
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->m_vRealPosition.goalv() + PWINDOWTOCHANGETO->m_vRealSize.goalv() / 2.f);
g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->middle());
};
CVarList vars(message, 0, ' ');
@@ -1066,44 +1318,87 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
recalculateMonitor(header.pWindow->m_iMonitorID);
} else if (command == "orientationnext") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
prepareLoseFocus(PWINDOW);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID);
if (PWORKSPACEDATA->orientation == ORIENTATION_CENTER) {
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
} else {
PWORKSPACEDATA->orientation = (eOrientation)(PWORKSPACEDATA->orientation + 1);
}
recalculateMonitor(header.pWindow->m_iMonitorID);
runOrientationCycle(header, nullptr, 1);
} else if (command == "orientationprev") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
prepareLoseFocus(PWINDOW);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID);
if (PWORKSPACEDATA->orientation == ORIENTATION_LEFT) {
PWORKSPACEDATA->orientation = ORIENTATION_CENTER;
} else {
PWORKSPACEDATA->orientation = (eOrientation)(PWORKSPACEDATA->orientation - 1);
runOrientationCycle(header, nullptr, -1);
} else if (command == "orientationcycle") {
runOrientationCycle(header, &vars, 1);
} else if (command == "mfact") {
if (vars.size() >= 2) {
float newMfact = 0;
try {
newMfact = std::stof(vars[1]);
} catch (std::exception& e) {
Debug::log(ERR, "Argument is invalid: {}", e.what());
return 0;
}
for (auto& nd : m_lMasterNodesData) {
if (nd.isMaster)
nd.percMaster = std::clamp(newMfact, 0.05f, 0.95f);
}
}
recalculateMonitor(header.pWindow->m_iMonitorID);
}
return 0;
}
// If vars is null, we use the default list
void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarList* vars, int direction) {
std::vector<eOrientation> cycle;
if (vars != nullptr)
buildOrientationCycleVectorFromVars(cycle, *vars);
if (cycle.size() == 0)
buildOrientationCycleVectorFromEOperation(cycle);
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return;
prepareLoseFocus(PWINDOW);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID);
int nextOrPrev = 0;
for (size_t i = 0; i < cycle.size(); ++i) {
if (PWORKSPACEDATA->orientation == cycle.at(i)) {
nextOrPrev = i + direction;
break;
}
}
if (nextOrPrev >= (int)cycle.size())
nextOrPrev = nextOrPrev % (int)cycle.size();
else if (nextOrPrev < 0)
nextOrPrev = cycle.size() + (nextOrPrev % (int)cycle.size());
PWORKSPACEDATA->orientation = cycle.at(nextOrPrev);
recalculateMonitor(header.pWindow->m_iMonitorID);
}
void CHyprMasterLayout::buildOrientationCycleVectorFromEOperation(std::vector<eOrientation>& cycle) {
for (int i = 0; i <= ORIENTATION_CENTER; ++i) {
cycle.push_back((eOrientation)i);
}
}
void CHyprMasterLayout::buildOrientationCycleVectorFromVars(std::vector<eOrientation>& cycle, CVarList& vars) {
for (size_t i = 1; i < vars.size(); ++i) {
if (vars[i] == "top") {
cycle.push_back(ORIENTATION_TOP);
} else if (vars[i] == "right") {
cycle.push_back(ORIENTATION_RIGHT);
} else if (vars[i] == "bottom") {
cycle.push_back(ORIENTATION_BOTTOM);
} else if (vars[i] == "left") {
cycle.push_back(ORIENTATION_LEFT);
} else if (vars[i] == "center") {
cycle.push_back(ORIENTATION_CENTER);
}
}
}
void CHyprMasterLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
const auto PNODE = getNodeFromWindow(from);

Some files were not shown because too many files have changed in this diff Show More