Compare commits

..

227 Commits

Author SHA1 Message Date
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
125 changed files with 4451 additions and 1970 deletions

View File

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

View File

@@ -15,10 +15,15 @@ jobs:
with: with:
submodules: recursive 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 - name: Create tarball with submodules
id: tar id: tar
run: | 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 * mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
- id: whatrelease - id: whatrelease

2
.gitignore vendored
View File

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

104
CMakeLists.txt Normal file → Executable file
View File

@@ -21,37 +21,51 @@ message(STATUS "Gathering git info")
# Get git info # Get git info
# hash and branch # hash and branch
execute_process( execute_process(
COMMAND git rev-parse --abbrev-ref HEAD COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 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)
# #
# #
# 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 = 12)([^032]|$$)/soversion = 12032/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.12032
INSTALL_COMMAND echo "wlroots: install not needed"
)
find_program(WaylandScanner NAMES wayland-scanner) find_program(WaylandScanner NAMES wayland-scanner)
message(STATUS "Found WaylandScanner at ${WaylandScanner}") message(STATUS "Found WaylandScanner at ${WaylandScanner}")
execute_process( execute_process(
@@ -93,6 +107,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wa
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
add_executable(Hyprland ${SRCFILES}) add_executable(Hyprland ${SRCFILES})
add_dependencies(Hyprland wlroots)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Setting debug flags") message(STATUS "Setting debug flags")
@@ -101,7 +116,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Enabling ASan") message(STATUS "Enabling ASan")
target_link_libraries(Hyprland asan) target_link_libraries(Hyprland asan)
add_compile_options(-fsanitize=address) target_compile_options(Hyprland PUBLIC -fsanitize=address)
endif() endif()
if(USE_TRACY) if(USE_TRACY)
@@ -123,6 +138,12 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
add_link_options(-pg -no-pie -fno-builtin) add_link_options(-pg -no-pie -fno-builtin)
endif() endif()
check_include_file("execinfo.h" EXECINFOH)
if(EXECINFOH)
message(STATUS "Configuration supports execinfo")
add_compile_definitions(HAS_EXECINFO)
endif()
include(CheckLibraryExists) include(CheckLibraryExists)
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO) check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
if(HAVE_LIBEXECINFO) if(HAVE_LIBEXECINFO)
@@ -147,24 +168,21 @@ if(NO_SYSTEMD)
message(STATUS "SYSTEMD support is disabled...") message(STATUS "SYSTEMD support is disabled...")
else() else()
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined) checking deps...") 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) check_include_file("systemd/sd-daemon.h" SYSTEMDH)
if(LIBSYSTEMD_FOUND AND SYSTEMDH) if(SYSTEMDH)
pkg_check_modules(LIBSYSTEMD libsystemd)
if (LIBSYSTEMD_FOUND)
add_compile_definitions(USES_SYSTEMD) add_compile_definitions(USES_SYSTEMD)
target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}") target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}")
message(STATUS "Systemd found")
else() else()
message(WARNING "Systemd support requested but libsystemd or systemd headers were not found") message(WARNING "Systemd support requested but systemd libraries were not found")
endif()
else()
message(WARNING "Systemd support requested but systemd headers were not found")
endif() endif()
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_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack) include(CPack)
@@ -202,7 +220,7 @@ target_link_libraries(Hyprland
OpenGL::EGL OpenGL::EGL
OpenGL::GL OpenGL::GL
Threads::Threads Threads::Threads
${CMAKE_SOURCE_DIR}/subprojects/udis86/build/libudis86/liblibudis86.a libudis86
) )
protocol("protocols/idle.xml" "idle" true) protocol("protocols/idle.xml" "idle" true)
@@ -218,5 +236,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/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("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/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("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) protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
# hyprctl
add_subdirectory(hyprctl)

View File

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

View File

@@ -41,6 +41,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
- Much more QoL stuff than other wlr-based compositors - Much more QoL stuff than other wlr-based compositors
- Custom bezier curves for the best animations - Custom bezier curves for the best animations
- Powerful plugin support - Powerful plugin support
- Tearing support for better gaming performance
- Easily expandable and readable codebase - Easily expandable and readable codebase
- Fast and active development - Fast and active development
- Not scared to provide bleeding-edge features - Not scared to provide bleeding-edge features

View File

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

View File

@@ -33,7 +33,7 @@ void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset
(m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying()); (m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
// draw the border // draw the border
wlr_box fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 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)}; (int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
fullBox.x -= pMonitor->vecPosition.x; fullBox.x -= pMonitor->vecPosition.x;
@@ -49,9 +49,9 @@ void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset
if (fullBox.width < 1 || fullBox.height < 1) if (fullBox.width < 1 || fullBox.height < 1)
return; // don't draw invisible shadows return; // don't draw invisible shadows
g_pHyprOpenGL->scissor((wlr_box*)nullptr); 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); g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
} }
@@ -68,7 +68,7 @@ void CCustomDecoration::updateWindow(CWindow* pWindow) {
} }
void CCustomDecoration::damageEntire() { void CCustomDecoration::damageEntire() {
wlr_box dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - 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}; (int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
g_pHyprRenderer->damageBox(&dm); 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::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, "activeWindow", [&](void* self, SCallbackInfo& info, std::any data) { onActiveWindowChange(self, data); });
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, std::any data) { onNewWindow(self, data); }); HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, SCallbackInfo& info, std::any data) { onNewWindow(self, data); });
g_pCustomLayout = std::make_unique<CHyprCustomLayout>(); g_pCustomLayout = std::make_unique<CHyprCustomLayout>();

View File

@@ -49,6 +49,9 @@ general {
col.inactive_border = rgba(595959aa) col.inactive_border = rgba(595959aa)
layout = dwindle layout = dwindle
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = false
} }
decoration { decoration {
@@ -60,6 +63,8 @@ decoration {
enabled = true enabled = true
size = 3 size = 3
passes = 1 passes = 1
vibrancy = 0.1696
} }
drop_shadow = true drop_shadow = true
@@ -99,6 +104,11 @@ gestures {
workspace_swipe = false 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 # Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more # See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
device:epic-mouse-v1 { device:epic-mouse-v1 {
@@ -155,6 +165,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9 bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10 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 # Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1 bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1 bind = $mainMod, mouse_up, workspace, e-1

20
flake.lock generated
View File

@@ -25,11 +25,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1694767346, "lastModified": 1698134075,
"narHash": "sha256-5uH27SiVFUwsTsqC5rs3kS7pBoNhtoy9QfTP9BmknGk=", "narHash": "sha256-foCD+nuKzfh49bIoiCBur4+Fx1nozo+4C/6k8BYk4sg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ace5093e36ab1e95cb9463863491bee90d5a4183", "rev": "8efd5d1e283604f75a808a20e6cde0ef313d07d4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -67,18 +67,18 @@
"flake": false, "flake": false,
"locked": { "locked": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"lastModified": 1695277534, "lastModified": 1699292815,
"narHash": "sha256-LEIUGXvKR5DYFQUTavC3yifcObvG4XZUUHfxXmu8nEM=", "narHash": "sha256-HXu98PyBMKEWLqiTb8viuLDznud/SdkdJsx5A5CWx7I=",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "98a745d926d8048bc30aef11b421df207a01c279", "rev": "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1",
"type": "gitlab" "type": "gitlab"
}, },
"original": { "original": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "98a745d926d8048bc30aef11b421df207a01c279", "rev": "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1",
"type": "gitlab" "type": "gitlab"
} }
}, },
@@ -95,11 +95,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1694628480, "lastModified": 1697981233,
"narHash": "sha256-Qg9hstRw0pvjGu5hStkr2UX1D73RYcQ9Ns/KnZMIm9w=", "narHash": "sha256-y8q4XUwx+gVK7i2eLjfR32lVo7TYvEslyzrmzYEaPZU=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "8f45a6435069b9e24ebd3160eda736d7a391cbf2", "rev": "22e7a65ff9633e1dedfa5317fdffc49f68de2ff2",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -12,7 +12,7 @@
host = "gitlab.freedesktop.org"; host = "gitlab.freedesktop.org";
owner = "wlroots"; owner = "wlroots";
repo = "wlroots"; repo = "wlroots";
rev = "98a745d926d8048bc30aef11b421df207a01c279"; rev = "5de9e1a99d6642c2d09d589aa37ff0a8945dcee1";
flake = false; flake = false;
}; };

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

@@ -29,6 +29,7 @@ commands:
monitors monitors
workspaces workspaces
activeworkspace activeworkspace
workspacerules
clients clients
activewindow activewindow
layers layers
@@ -273,7 +274,6 @@ bool isNumber(const std::string& str, bool allowfloat) {
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
int bflag = 0, sflag = 0, index, c;
bool parseArgs = true; bool parseArgs = true;
if (argc < 2) { if (argc < 2) {
@@ -287,7 +287,7 @@ int main(int argc, char** argv) {
bool json = false; bool json = false;
std::string overrideInstance = ""; std::string overrideInstance = "";
for (auto i = 0; i < ARGS.size(); ++i) { for (std::size_t i = 0; i < ARGS.size(); ++i) {
if (ARGS[i] == "--") { if (ARGS[i] == "--") {
// Stop parsing arguments after -- // Stop parsing arguments after --
parseArgs = false; parseArgs = false;
@@ -341,7 +341,7 @@ int main(int argc, char** argv) {
const auto INSTANCES = instances(); 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"; std::cout << "no such instance\n";
return 1; return 1;
} }
@@ -370,6 +370,8 @@ int main(int argc, char** argv) {
request(fullRequest); request(fullRequest);
else if (fullRequest.contains("/activeworkspace")) else if (fullRequest.contains("/activeworkspace"))
request(fullRequest); request(fullRequest);
else if (fullRequest.contains("/workspacerules"))
request(fullRequest);
else if (fullRequest.contains("/activewindow")) else if (fullRequest.contains("/activewindow"))
request(fullRequest); request(fullRequest);
else if (fullRequest.contains("/layers")) else if (fullRequest.contains("/layers"))

View File

@@ -20,25 +20,19 @@ else
error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)')
endif 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( add_project_arguments(
[ [
'-Wno-unused-parameter', '-Wno-unused-parameter',
'-Wno-unused-value', '-Wno-unused-value',
'-Wno-missing-field-initializers', '-Wno-missing-field-initializers',
'-Wno-narrowing', '-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') language: 'cpp')
if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif
wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2']) wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
have_xwlr = wlroots.get_variable('features').get('xwayland') have_xwlr = wlroots.get_variable('features').get('xwayland')
xcb_dep = dependency('xcb', required: get_option('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') add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
endif endif
version_h = run_command('sh', '-c', 'scripts/generateVersion.sh')
globber = run_command('find', 'src', '-name', '*.h*', check: true) globber = run_command('find', 'src', '-name', '*.h*', check: true)
headers = globber.stdout().strip().split('\n') headers = globber.stdout().strip().split('\n')
foreach file : headers foreach file : headers

View File

@@ -90,8 +90,9 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
then "debug" then "debug"
else "release"; else "release";
mesonAutoFeatures = "disabled";
mesonFlags = builtins.concatLists [ mesonFlags = builtins.concatLists [
["-Dauto_features=disabled"]
(lib.optional enableXWayland "-Dxwayland=enabled") (lib.optional enableXWayland "-Dxwayland=enabled")
(lib.optional legacyRenderer "-Dlegacy_renderer=enabled") (lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
(lib.optional withSystemd "-Dsystemd=enabled") (lib.optional withSystemd "-Dsystemd=enabled")
@@ -105,9 +106,15 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
postPatch = '' postPatch = ''
# Fix hardcoded paths to /usr installation # Fix hardcoded paths to /usr installation
sed -i "s#/usr#$out#" src/render/OpenGL.cpp sed -i "s#/usr#$out#" src/render/OpenGL.cpp
substituteInPlace meson.build \
--replace "@GIT_COMMIT_HASH@" '${commit}' \ # Generate version.h
--replace "@GIT_DIRTY@" '${ 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 == "" if commit == ""
then "dirty" then "dirty"
else "" else ""

View File

@@ -1,23 +1,11 @@
diff --git a/meson.build b/meson.build diff --git a/meson.build b/meson.build
index f3802553..6a924a79 100644 index 1d2c7f9f..c5ef4e67 100644
--- a/meson.build --- a/meson.build
+++ b/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 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', 'renderers=gles2']) -wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
-have_xwlr = wlroots.get_variable('features').get('xwayland') -have_xwlr = wlroots.get_variable('features').get('xwayland')
-xcb_dep = dependency('xcb', required: get_option('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 -have_xwayland = xcb_dep.found() and have_xwlr
- -
-if not have_xwayland -if not have_xwayland
- add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
+if get_option('xwayland').disabled() +if get_option('xwayland').disabled()
+ add_project_arguments('-DNO_XWAYLAND', language: 'cpp') add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif 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 diff --git a/src/meson.build b/src/meson.build
index 7b658d31..60aa4057 100644 index 0af864b9..38723b8c 100644
--- a/src/meson.build --- a/src/meson.build
+++ b/src/meson.build +++ b/src/meson.build
@@ -7,16 +7,16 @@ executable('Hyprland', src, @@ -9,16 +9,16 @@ executable('Hyprland', src,
server_protos, server_protos,
dependency('wayland-server'), dependency('wayland-server'),
dependency('wayland-client'), dependency('wayland-client'),

View File

@@ -1,3 +1,3 @@
{ {
"version": "0.30.0" "version": "0.32.2"
} }

View File

@@ -25,6 +25,7 @@ protocols = [
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], [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/fractional-scale/fractional-scale-v1.xml'],
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-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-foreign-toplevel-management-unstable-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'],
['wlr-output-power-management-unstable-v1.xml'], ['wlr-output-power-management-unstable-v1.xml'],

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

View File

@@ -34,6 +34,13 @@ void handleUnrecoverableSignal(int sig) {
abort(); abort();
} }
void handleUserSignal(int sig) {
if (sig == SIGUSR1) {
// means we have to unwind a timed out event
throw std::exception();
}
}
CCompositor::CCompositor() { CCompositor::CCompositor() {
m_iHyprlandPID = getpid(); m_iHyprlandPID = getpid();
@@ -74,6 +81,7 @@ CCompositor::CCompositor() {
CCompositor::~CCompositor() { CCompositor::~CCompositor() {
cleanup(); cleanup();
g_pDecorationPositioner.reset();
g_pPluginSystem.reset(); g_pPluginSystem.reset();
g_pHyprNotificationOverlay.reset(); g_pHyprNotificationOverlay.reset();
g_pDebugOverlay.reset(); g_pDebugOverlay.reset();
@@ -92,6 +100,7 @@ CCompositor::~CCompositor() {
g_pAnimationManager.reset(); g_pAnimationManager.reset();
g_pKeybindManager.reset(); g_pKeybindManager.reset();
g_pHookSystem.reset(); g_pHookSystem.reset();
g_pWatchdog.reset();
} }
void CCompositor::setRandomSplash() { void CCompositor::setRandomSplash() {
@@ -112,7 +121,7 @@ void CCompositor::initServer() {
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr); wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
signal(SIGSEGV, handleUnrecoverableSignal); signal(SIGSEGV, handleUnrecoverableSignal);
signal(SIGABRT, handleUnrecoverableSignal); signal(SIGABRT, handleUnrecoverableSignal);
//wl_event_loop_add_signal(m_sWLEventLoop, SIGINT, handleCritSignal, nullptr); signal(SIGUSR1, handleUserSignal);
initManagers(STAGE_PRIORITY); initManagers(STAGE_PRIORITY);
@@ -124,6 +133,8 @@ void CCompositor::initServer() {
const auto LOGWLR = getenv("HYPRLAND_LOG_WLR"); const auto LOGWLR = getenv("HYPRLAND_LOG_WLR");
if (LOGWLR && std::string(LOGWLR) == "1") if (LOGWLR && std::string(LOGWLR) == "1")
wlr_log_init(WLR_DEBUG, Debug::wlrLog); wlr_log_init(WLR_DEBUG, Debug::wlrLog);
else
wlr_log_init(WLR_ERROR, Debug::wlrLog);
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay, &m_sWLRSession); m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay, &m_sWLRSession);
@@ -204,7 +215,6 @@ void CCompositor::initServer() {
m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend); m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend);
m_sWLRIdle = wlr_idle_create(m_sWLDisplay);
m_sWLRIdleNotifier = wlr_idle_notifier_v1_create(m_sWLDisplay); m_sWLRIdleNotifier = wlr_idle_notifier_v1_create(m_sWLDisplay);
m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay, 4); m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay, 4);
@@ -257,6 +267,8 @@ void CCompositor::initServer() {
m_sWLRCursorShapeMgr = wlr_cursor_shape_manager_v1_create(m_sWLDisplay, 1); m_sWLRCursorShapeMgr = wlr_cursor_shape_manager_v1_create(m_sWLDisplay, 1);
m_sWLRTearingControlMgr = wlr_tearing_control_manager_v1_create(m_sWLDisplay, 1);
if (!m_sWLRHeadlessBackend) { if (!m_sWLRHeadlessBackend) {
Debug::log(CRIT, "Couldn't create the headless backend"); Debug::log(CRIT, "Couldn't create the headless backend");
throwError("wlr_headless_backend_create() failed!"); throwError("wlr_headless_backend_create() failed!");
@@ -315,6 +327,7 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRSessionLockMgr->events.new_lock, &Events::listen_newSessionLock, m_sWLRSessionLockMgr, "SessionLockMgr"); addWLSignal(&m_sWLRSessionLockMgr->events.new_lock, &Events::listen_newSessionLock, m_sWLRSessionLockMgr, "SessionLockMgr");
addWLSignal(&m_sWLRGammaCtrlMgr->events.set_gamma, &Events::listen_setGamma, m_sWLRGammaCtrlMgr, "GammaCtrlMgr"); addWLSignal(&m_sWLRGammaCtrlMgr->events.set_gamma, &Events::listen_setGamma, m_sWLRGammaCtrlMgr, "GammaCtrlMgr");
addWLSignal(&m_sWLRCursorShapeMgr->events.request_set_shape, &Events::listen_setCursorShape, m_sWLRCursorShapeMgr, "CursorShapeMgr"); addWLSignal(&m_sWLRCursorShapeMgr->events.request_set_shape, &Events::listen_setCursorShape, m_sWLRCursorShapeMgr, "CursorShapeMgr");
addWLSignal(&m_sWLRTearingControlMgr->events.new_object, &Events::listen_newTearingHint, m_sWLRTearingControlMgr, "TearingControlMgr");
if (m_sWRLDRMLeaseMgr) if (m_sWRLDRMLeaseMgr)
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM"); addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
@@ -392,6 +405,7 @@ void CCompositor::initManagers(eManagersInitStage stage) {
g_pLayoutManager = std::make_unique<CLayoutManager>(); g_pLayoutManager = std::make_unique<CLayoutManager>();
g_pConfigManager->init(); g_pConfigManager->init();
g_pWatchdog = std::make_unique<CWatchdog>(); // requires config
} break; } break;
case STAGE_LATE: { case STAGE_LATE: {
Debug::log(LOG, "Creating the ThreadManager!"); Debug::log(LOG, "Creating the ThreadManager!");
@@ -428,6 +442,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the PluginSystem!"); Debug::log(LOG, "Creating the PluginSystem!");
g_pPluginSystem = std::make_unique<CPluginSystem>(); g_pPluginSystem = std::make_unique<CPluginSystem>();
g_pConfigManager->handlePluginLoads(); g_pConfigManager->handlePluginLoads();
Debug::log(LOG, "Creating the DecorationPositioner!");
g_pDecorationPositioner = std::make_unique<CDecorationPositioner>();
} break; } break;
default: UNREACHABLE(); default: UNREACHABLE();
} }
@@ -450,6 +467,25 @@ void CCompositor::removeLockFile() {
std::filesystem::remove(PATH); std::filesystem::remove(PATH);
} }
void CCompositor::prepareFallbackOutput() {
// create a backup monitor
wlr_backend* headless = nullptr;
wlr_multi_for_each_backend(
m_sWLRBackend,
[](wlr_backend* b, void* data) {
if (wlr_backend_is_headless(b))
*((wlr_backend**)data) = b;
},
&headless);
if (!headless) {
Debug::log(WARN, "Unsafe state will be ineffective, no fallback output");
return;
}
wlr_headless_add_output(headless, 1920, 1080);
}
void CCompositor::startCompositor() { void CCompositor::startCompositor() {
initAllSignals(); initAllSignals();
@@ -501,7 +537,9 @@ void CCompositor::startCompositor() {
throwError("The backend could not start!"); throwError("The backend could not start!");
} }
wlr_cursor_set_xcursor(m_sWLRCursor, m_sWLRXCursorMgr, "left_ptr"); prepareFallbackOutput();
g_pHyprRenderer->setCursorFromName("left_ptr");
#ifdef USES_SYSTEMD #ifdef USES_SYSTEMD
if (sd_booted() > 0) if (sd_booted() > 0)
@@ -539,7 +577,7 @@ CMonitor* CCompositor::getMonitorFromName(const std::string& name) {
CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) { CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) {
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
if (m->output->description && std::string(m->output->description).find(desc) == 0) if (m->output->description && std::string(m->output->description).starts_with(desc))
return m.get(); return m.get();
} }
return nullptr; return nullptr;
@@ -597,38 +635,35 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceID) { if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; auto box = w->getWindowMainSurfaceBox();
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() && if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bNoFocus)
!w->m_bNoFocus)
return w.get(); return w.get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; auto box = w->getWindowMainSurfaceBox();
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden() && if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint(pos) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
!w->m_bNoFocus)
return w.get(); return w.get();
} }
} }
// pinned // pinned
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; auto box = w->getWindowMainSurfaceBox();
if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus) if (box.containsPoint(pos) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
return w.get(); return w.get();
} }
// first loop over floating cuz they're above, m_vWindows should be sorted bottom->top, for tiled it doesn't matter. // first loop over floating cuz they're above, m_vWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; auto box = w->getWindowMainSurfaceBox();
if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && if (box.containsPoint(pos) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus)
!w->m_bNoFocus)
return w.get(); return w.get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; auto box = w->getWindowMainSurfaceBox();
if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->isHidden() && !w->m_bNoFocus) if (box.containsPoint(pos) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->isHidden() && !w->m_bNoFocus)
return w.get(); return w.get();
} }
@@ -640,15 +675,15 @@ CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceID) { if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus) if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint(pos) && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get(); return w.get();
} }
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus) if (w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get(); return w.get();
} }
@@ -666,16 +701,16 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceID) { if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowInputBox(); const auto BB = w->getWindowInputBox();
wlr_box box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA}; CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() && if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_bX11ShouldntFocus && !w->m_bNoFocus) !w->m_bNoFocus)
return w.get(); return w.get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() && if (!w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_bX11ShouldntFocus && !w->m_bNoFocus) !w->m_bNoFocus)
return w.get(); return w.get();
} }
} }
@@ -683,9 +718,9 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// pinned windows on top of floating regardless // pinned windows on top of floating regardless
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowInputBox(); const auto BB = w->getWindowInputBox();
wlr_box box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA}; CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus) { if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus) {
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y)) if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
return w.get(); return w.get();
if (!w->m_bIsX11) { if (!w->m_bIsX11) {
@@ -698,13 +733,13 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowInputBox(); const auto BB = w->getWindowInputBox();
wlr_box box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA}; CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus) { if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus) {
// OR windows should add focus to parent // OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2) if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
continue; continue;
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y)) { if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) { if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
// Override Redirect // Override Redirect
@@ -730,9 +765,9 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
} }
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_bX11ShouldntFocus && !w->m_bNoFocus) !w->m_bNoFocus)
return w.get(); return w.get();
} }
@@ -744,37 +779,36 @@ CWindow* CCompositor::windowFromCursor() {
if (PMONITOR->specialWorkspaceID) { if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) &&
!w->isHidden() && !w->m_bNoFocus) !w->isHidden() && !w->m_bNoFocus)
return w.get(); return w.get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && !w->m_bNoFocus) if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && !w->m_bNoFocus)
return w.get(); return w.get();
} }
} }
// pinned // pinned
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && w->m_bPinned && !w->m_bNoFocus) if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && w->m_bPinned && !w->m_bNoFocus)
return w.get(); return w.get();
} }
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bPinned && if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bPinned && !w->m_bNoFocus)
!w->m_bNoFocus)
return w.get(); return w.get();
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y}; CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bNoFocus) if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bNoFocus)
return w.get(); return w.get();
} }
@@ -783,14 +817,14 @@ CWindow* CCompositor::windowFromCursor() {
CWindow* CCompositor::windowFloatingFromCursor() { CWindow* CCompositor::windowFloatingFromCursor() {
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus) if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
return w.get(); return w.get();
} }
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() &&
!w->m_bPinned && !w->m_bNoFocus) !w->m_bPinned && !w->m_bNoFocus)
return w.get(); return w.get();
} }
@@ -810,8 +844,9 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
double subx, suby; double subx, suby;
// calc for oversized windows... fucking bullshit, again. // calc for oversized windows... fucking bullshit, again.
wlr_box geom; CBox geom;
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom); wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, geom.pWlr());
geom.applyFromWlr();
const auto PFOUND = wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.vec().x + geom.x, pos.y - pWindow->m_vRealPosition.vec().y + geom.y, &subx, &suby); const auto PFOUND = wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.vec().x + geom.x, pos.y - pWindow->m_vRealPosition.vec().y + geom.y, &subx, &suby);
@@ -830,6 +865,38 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
return PSURFACE->surface; return PSURFACE->surface;
} }
Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, CWindow* pWindow, wlr_surface* pSurface) {
if (!windowValidMapped(pWindow))
return {};
if (pWindow->m_bIsX11)
return vec - pWindow->m_vRealPosition.goalv();
const auto PSURFACE = pWindow->m_uSurface.xdg;
std::tuple<wlr_surface*, int, int> iterData = {pSurface, -1337, -1337};
wlr_xdg_surface_for_each_surface(
PSURFACE,
[](wlr_surface* surf, int x, int y, void* data) {
const auto PDATA = (std::tuple<wlr_surface*, int, int>*)data;
if (surf == std::get<0>(*PDATA)) {
std::get<1>(*PDATA) = x;
std::get<2>(*PDATA) = y;
}
},
&iterData);
CBox geom = {};
wlr_xdg_surface_get_geometry(PSURFACE, geom.pWlr());
geom.applyFromWlr();
if (std::get<1>(iterData) == -1337 && std::get<2>(iterData) == -1337)
return vec - pWindow->m_vRealPosition.goalv();
return vec - pWindow->m_vRealPosition.goalv() - Vector2D{std::get<1>(iterData), std::get<2>(iterData)} + Vector2D{geom.x, geom.y};
}
CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) { CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
if (m->output == out) { if (m->output == out) {
@@ -842,6 +909,8 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) { void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
if (g_pCompositor->m_sSeat.exclusiveClient) { if (g_pCompositor->m_sSeat.exclusiveClient) {
Debug::log(LOG, "Disallowing setting focus to a window due to there being an active input inhibitor layer."); Debug::log(LOG, "Disallowing setting focus to a window due to there being an active input inhibitor layer.");
return; return;
@@ -850,6 +919,10 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow); g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
if (!pWindow || !windowValidMapped(pWindow)) { if (!pWindow || !windowValidMapped(pWindow)) {
if (!m_pLastWindow && !pWindow)
return;
const auto PLASTWINDOW = m_pLastWindow; const auto PLASTWINDOW = m_pLastWindow;
m_pLastWindow = nullptr; m_pLastWindow = nullptr;
@@ -961,6 +1034,9 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
} else { } else {
std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1); std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1);
} }
if (*PFOLLOWMOUSE == 0)
g_pInputManager->sendMotionEventsToFocused();
} }
void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) { void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
@@ -1141,28 +1217,40 @@ void CCompositor::sanityCheckWorkspaces() {
auto it = m_vWorkspaces.begin(); auto it = m_vWorkspaces.begin();
while (it != m_vWorkspaces.end()) { while (it != m_vWorkspaces.end()) {
if ((*it)->m_bIndestructible) const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(it->get());
continue; if (WORKSPACERULE.isPersistent) {
const auto WINDOWSONWORKSPACE = getWindowsOnWorkspace((*it)->m_iID);
if ((WINDOWSONWORKSPACE == 0 && !isWorkspaceVisible((*it)->m_iID))) {
if ((*it)->m_bIsSpecialWorkspace) {
if ((*it)->m_fAlpha.fl() > 0.f /* don't abruptly end the fadeout */) {
++it; ++it;
continue; continue;
} }
const auto PMONITOR = getMonitorFromID((*it)->m_iMonitorID); const auto& WORKSPACE = *it;
const auto WINDOWSONWORKSPACE = getWindowsOnWorkspace(WORKSPACE->m_iID);
if (PMONITOR && PMONITOR->specialWorkspaceID == (*it)->m_iID) if (WINDOWSONWORKSPACE == 0) {
if (!isWorkspaceVisible(WORKSPACE->m_iID)) {
if (WORKSPACE->m_bIsSpecialWorkspace) {
if (WORKSPACE->m_fAlpha.fl() > 0.f /* don't abruptly end the fadeout */) {
++it;
continue;
}
const auto PMONITOR = getMonitorFromID(WORKSPACE->m_iMonitorID);
if (PMONITOR && PMONITOR->specialWorkspaceID == WORKSPACE->m_iID)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
it = m_vWorkspaces.erase(it); it = m_vWorkspaces.erase(it);
continue; continue;
} }
if (!WORKSPACE->m_bOnCreatedEmptyExecuted) {
if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd)
g_pKeybindManager->spawn(*cmd);
WORKSPACE->m_bOnCreatedEmptyExecuted = true;
}
}
++it; ++it;
} }
@@ -1417,22 +1505,37 @@ void CCompositor::addToFadingOutSafe(CWindow* pWindow) {
CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
if (!isDirection(dir))
return nullptr;
// 0 -> history, 1 -> shared length // 0 -> history, 1 -> shared length
static auto* const PMETHOD = &g_pConfigManager->getConfigValuePtr("binds:focus_preferred_method")->intValue; static auto* const PMETHOD = &g_pConfigManager->getConfigValuePtr("binds:focus_preferred_method")->intValue;
const auto WINDOWIDEALBB = pWindow->getWindowIdealBoundingBoxIgnoreReserved(); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
if (!PMONITOR)
return nullptr; // ??
const auto WINDOWIDEALBB = pWindow->m_bIsFullscreen ? wlr_box{(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y} :
pWindow->getWindowIdealBoundingBoxIgnoreReserved();
const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y); const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y);
const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height); const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
auto leaderValue = -1; auto leaderValue = -1;
CWindow* leaderWindow = nullptr; CWindow* leaderWindow = nullptr;
if (!pWindow->m_bIsFloating) {
// for tiled windows, we calc edges
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID)) if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID))
continue; continue;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID); if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID)
continue;
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen)
continue; continue;
@@ -1494,6 +1597,53 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
} }
} }
} }
} else {
// for floating windows, we calculate best distance and angle.
// if there is a window with angle better than THRESHOLD, only distance counts
if (dir == 'u')
dir = 't';
if (dir == 'd')
dir = 'b';
static const std::unordered_map<char, Vector2D> VECTORS = {{'r', {1, 0}}, {'t', {0, -1}}, {'b', {0, 1}}, {'l', {-1, 0}}};
//
auto vectorAngles = [](Vector2D a, Vector2D b) -> double {
double dot = a.x * b.x + a.y * b.y;
double ang = std::acos(dot / (a.size() * b.size()));
return ang;
};
float bestAngleAbs = 2.0 * M_PI;
constexpr float THRESHOLD = 0.3 * M_PI;
for (auto& w : m_vWindows) {
if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || !w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID))
continue;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID)
continue;
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen)
continue;
const auto DIST = w->middle().distance(pWindow->middle());
const auto ANGLE = vectorAngles(Vector2D{w->middle() - pWindow->middle()}, VECTORS.at(dir));
if (ANGLE > M_PI_2)
continue; // if the angle is over 90 degrees, ignore. Wrong direction entirely.
if ((bestAngleAbs < THRESHOLD && DIST < leaderValue && ANGLE < THRESHOLD) || (ANGLE < bestAngleAbs && bestAngleAbs > THRESHOLD) || leaderValue == -1) {
leaderValue = DIST;
bestAngleAbs = ANGLE;
leaderWindow = w.get();
}
}
if (!leaderWindow && PWORKSPACE->m_bHasFullscreenWindow)
leaderWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
}
if (leaderValue != -1) if (leaderValue != -1)
return leaderWindow; return leaderWindow;
@@ -1567,7 +1717,7 @@ CWorkspace* CCompositor::getWorkspaceByName(const std::string& name) {
} }
CWorkspace* CCompositor::getWorkspaceByString(const std::string& str) { CWorkspace* CCompositor::getWorkspaceByString(const std::string& str) {
if (str.find("name:") == 0) { if (str.starts_with("name:")) {
return getWorkspaceByName(str.substr(str.find_first_of(':') + 1)); return getWorkspaceByName(str.substr(str.find_first_of(':') + 1));
} }
@@ -1694,10 +1844,10 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
static auto* const INACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->data.get(); static auto* const INACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->data.get();
static auto* const NOGROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border_active")->data.get(); static auto* const NOGROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border_active")->data.get();
static auto* const NOGROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border")->data.get(); static auto* const NOGROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border")->data.get();
static auto* const GROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border_active")->data.get(); static auto* const GROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_active")->data.get();
static auto* const GROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border")->data.get(); static auto* const GROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_inactive")->data.get();
static auto* const GROUPACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border_locked_active")->data.get(); static auto* const GROUPACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_active")->data.get();
static auto* const GROUPINACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border_locked")->data.get(); static auto* const GROUPINACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_inactive")->data.get();
static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue; static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue; static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
static auto* const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue; static auto* const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue;
@@ -1774,8 +1924,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow
} }
for (auto& d : pWindow->m_dWindowDecorations) pWindow->updateWindowDecos();
d->updateWindow(pWindow);
} }
int CCompositor::getNextAvailableMonitorID(std::string const& name) { int CCompositor::getNextAvailableMonitorID(std::string const& name) {
@@ -1926,14 +2075,14 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1"); Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1");
return nullptr; return nullptr;
} }
} else if (name.find("desc:") == 0) { } else if (name.starts_with("desc:")) {
const auto DESCRIPTION = name.substr(5); const auto DESCRIPTION = name.substr(5);
for (auto& m : m_vMonitors) { for (auto& m : m_vMonitors) {
if (!m->output) if (!m->output)
continue; continue;
if (m->output->description && std::string(m->output->description).find(DESCRIPTION) == 0) { if (m->output->description && std::string(m->output->description).starts_with(DESCRIPTION)) {
return m.get(); return m.get();
} }
} }
@@ -2108,7 +2257,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(CWorkspace* pWorkspace) {
} }
void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode mode) { void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode mode) {
if (!windowValidMapped(pWindow)) if (!windowValidMapped(pWindow) || g_pCompositor->m_bUnsafeState)
return; return;
if (pWindow->m_bPinned) { if (pWindow->m_bPinned) {
@@ -2120,14 +2269,16 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID);
const auto MODE = mode == FULLSCREEN_INVALID ? PWORKSPACE->m_efFullscreenMode : mode;
if (PWORKSPACE->m_bHasFullscreenWindow && on) { if (PWORKSPACE->m_bHasFullscreenWindow && on) {
Debug::log(LOG, "Rejecting fullscreen ON on a fullscreen workspace"); Debug::log(LOG, "Rejecting fullscreen ON on a fullscreen workspace");
return; return;
} }
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, mode, on); g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, MODE, on);
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL); g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && MODE == FULLSCREEN_FULL);
pWindow->updateDynamicRules(); pWindow->updateDynamicRules();
updateWindowAnimatedDecorationValues(pWindow); updateWindowAnimatedDecorationValues(pWindow);
@@ -2193,15 +2344,30 @@ CWindow* CCompositor::getWindowByRegex(const std::string& regexp) {
std::regex regexCheck(regexp); std::regex regexCheck(regexp);
std::string matchCheck; std::string matchCheck;
if (regexp.find("title:") == 0) { if (regexp.starts_with("title:")) {
mode = MODE_TITLE_REGEX; mode = MODE_TITLE_REGEX;
regexCheck = std::regex(regexp.substr(6)); regexCheck = std::regex(regexp.substr(6));
} else if (regexp.find("address:") == 0) { } else if (regexp.starts_with("address:")) {
mode = MODE_ADDRESS; mode = MODE_ADDRESS;
matchCheck = regexp.substr(8); matchCheck = regexp.substr(8);
} else if (regexp.find("pid:") == 0) { } else if (regexp.starts_with("pid:")) {
mode = MODE_PID; mode = MODE_PID;
matchCheck = regexp.substr(4); matchCheck = regexp.substr(4);
} else if (regexp.starts_with("floating") || regexp.starts_with("tiled")) {
// first floating on the current ws
if (!m_pLastWindow)
return nullptr;
const bool FLOAT = regexp.starts_with("floating");
for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_iWorkspaceID != m_pLastWindow->m_iWorkspaceID || w->isHidden())
continue;
return w.get();
}
return nullptr;
} }
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
@@ -2445,7 +2611,13 @@ int CCompositor::getNewSpecialID() {
} }
void CCompositor::performUserChecks() { void CCompositor::performUserChecks() {
// empty const auto atomicEnv = getenv("WLR_DRM_NO_ATOMIC");
const auto atomicEnvStr = std::string(atomicEnv ? atomicEnv : "");
if (g_pConfigManager->getInt("general:allow_tearing") == 1 && atomicEnvStr != "1") {
g_pHyprNotificationOverlay->addNotification("You have enabled tearing, but immediate presentations are not available on your configuration. Try adding "
"env = WLR_DRM_NO_ATOMIC,1 to your config.",
CColor(0), 15000, ICON_WARNING);
}
} }
void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) { void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) {
@@ -2510,12 +2682,10 @@ CWindow* CCompositor::getForceFocus() {
} }
void CCompositor::notifyIdleActivity() { void CCompositor::notifyIdleActivity() {
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
wlr_idle_notifier_v1_notify_activity(g_pCompositor->m_sWLRIdleNotifier, g_pCompositor->m_sSeat.seat); wlr_idle_notifier_v1_notify_activity(g_pCompositor->m_sWLRIdleNotifier, g_pCompositor->m_sSeat.seat);
} }
void CCompositor::setIdleActivityInhibit(bool enabled) { void CCompositor::setIdleActivityInhibit(bool enabled) {
wlr_idle_set_enabled(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat, enabled);
wlr_idle_notifier_v1_set_inhibited(g_pCompositor->m_sWLRIdleNotifier, !enabled); wlr_idle_notifier_v1_set_inhibited(g_pCompositor->m_sWLRIdleNotifier, !enabled);
} }
void CCompositor::arrangeMonitors() { void CCompositor::arrangeMonitors() {
@@ -2576,3 +2746,50 @@ void CCompositor::arrangeMonitors() {
m->xwaylandScale = 1.f; m->xwaylandScale = 1.f;
} }
} }
void CCompositor::enterUnsafeState() {
if (m_bUnsafeState)
return;
Debug::log(LOG, "Entering unsafe state");
if (!m_pUnsafeOutput->m_bEnabled)
m_pUnsafeOutput->onConnect(false);
m_bUnsafeState = true;
}
void CCompositor::leaveUnsafeState() {
if (!m_bUnsafeState)
return;
Debug::log(LOG, "Leaving unsafe state");
m_bUnsafeState = false;
CMonitor* pNewMonitor = nullptr;
for (auto& pMonitor : m_vMonitors) {
if (pMonitor->output != m_pUnsafeOutput->output) {
pNewMonitor = pMonitor.get();
break;
}
}
RASSERT(pNewMonitor, "Tried to leave unsafe without a monitor");
if (m_pUnsafeOutput->m_bEnabled)
m_pUnsafeOutput->onDisconnect();
for (auto& m : m_vMonitors) {
scheduleFrameForMonitor(m.get());
}
}
void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) {
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(pSurface, scale);
wlr_surface_set_preferred_buffer_scale(pSurface, static_cast<int32_t>(std::ceil(scale)));
}
void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) {
wlr_surface_set_preferred_buffer_transform(pSurface, transform);
}

View File

@@ -27,8 +27,10 @@
#include "render/OpenGL.hpp" #include "render/OpenGL.hpp"
#include "hyprerror/HyprError.hpp" #include "hyprerror/HyprError.hpp"
#include "plugins/PluginSystem.hpp" #include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp"
enum eManagersInitStage { enum eManagersInitStage
{
STAGE_PRIORITY = 0, STAGE_PRIORITY = 0,
STAGE_LATE STAGE_LATE
}; };
@@ -52,7 +54,6 @@ class CCompositor {
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_xdg_activation_v1* m_sWLRXDGActivation; wlr_xdg_activation_v1* m_sWLRXDGActivation;
wlr_output_layout* m_sWLROutputLayout; wlr_output_layout* m_sWLROutputLayout;
wlr_idle* m_sWLRIdle;
wlr_idle_notifier_v1* m_sWLRIdleNotifier; wlr_idle_notifier_v1* m_sWLRIdleNotifier;
wlr_layer_shell_v1* m_sWLRLayerShell; wlr_layer_shell_v1* m_sWLRLayerShell;
wlr_xdg_shell* m_sWLRXDGShell; wlr_xdg_shell* m_sWLRXDGShell;
@@ -84,6 +85,7 @@ class CCompositor {
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr; wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr; wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr; wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr;
wlr_tearing_control_manager_v1* m_sWLRTearingControlMgr;
// ------------------------------------------------- // // ------------------------------------------------- //
std::string m_szWLDisplaySocket = ""; std::string m_szWLDisplaySocket = "";
@@ -119,6 +121,8 @@ class CCompositor {
bool m_bSessionActive = true; bool m_bSessionActive = true;
bool m_bDPMSStateON = true; bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; // because wlroots
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bIsShuttingDown = false; bool m_bIsShuttingDown = false;
// ------------------------------------------------- // // ------------------------------------------------- //
@@ -138,6 +142,7 @@ class CCompositor {
CWindow* vectorToWindowTiled(const Vector2D&); CWindow* vectorToWindowTiled(const Vector2D&);
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**); wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl); wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
CWindow* windowFromCursor(); CWindow* windowFromCursor();
CWindow* windowFloatingFromCursor(); CWindow* windowFloatingFromCursor();
CMonitor* getMonitorFromOutput(wlr_output*); CMonitor* getMonitorFromOutput(wlr_output*);
@@ -200,6 +205,10 @@ class CCompositor {
void notifyIdleActivity(); void notifyIdleActivity();
void setIdleActivityInhibit(bool inhibit); void setIdleActivityInhibit(bool inhibit);
void arrangeMonitors(); 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; std::string explicitConfigPath;
@@ -207,6 +216,7 @@ class CCompositor {
void initAllSignals(); void initAllSignals();
void setRandomSplash(); void setRandomSplash();
void initManagers(eManagersInitStage stage); void initManagers(eManagersInitStage stage);
void prepareFallbackOutput();
uint64_t m_iHyprlandPID = 0; uint64_t m_iHyprlandPID = 0;
}; };

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include "helpers/Vector2D.hpp"
enum eIcons enum eIcons
{ {
ICON_WARNING = 0, ICON_WARNING = 0,
@@ -23,3 +25,25 @@ enum eRenderStage
RENDER_PRE_WINDOW, /* Before rendering a window (any pass) Note some windows (e.g. tiled) may have 2 passes (main & popup) */ 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) */ 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

@@ -13,7 +13,7 @@ CWindow::CWindow() {
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW); m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE); m_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() { CWindow::~CWindow() {
@@ -37,9 +37,7 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; 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) if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x; maxExtents.topLeft.x = EXTENTS.topLeft.x;
@@ -52,15 +50,14 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y) if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y; maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
}
if (m_pWLSurface.exists() && !m_bIsX11) { 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? // TODO: this could be better, perhaps make a getFullWindowRegion?
wlr_xdg_surface_for_each_popup_surface( wlr_xdg_surface_for_each_popup_surface(
m_uSurface.xdg, m_uSurface.xdg,
[](wlr_surface* surf, int sx, int sy, void* data) { [](wlr_surface* surf, int sx, int sy, void* data) {
wlr_box* pSurfaceExtents = (wlr_box*)data; CBox* pSurfaceExtents = (CBox*)data;
if (sx < pSurfaceExtents->x) if (sx < pSurfaceExtents->x)
pSurfaceExtents->x = sx; pSurfaceExtents->x = sx;
if (sy < pSurfaceExtents->y) if (sy < pSurfaceExtents->y)
@@ -88,7 +85,7 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
return maxExtents; return maxExtents;
} }
wlr_box CWindow::getFullWindowBoundingBox() { CBox CWindow::getFullWindowBoundingBox() {
if (m_sAdditionalConfigData.dimAround) { if (m_sAdditionalConfigData.dimAround) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
@@ -96,13 +93,13 @@ wlr_box CWindow::getFullWindowBoundingBox() {
auto maxExtents = getFullWindowExtents(); auto maxExtents = getFullWindowExtents();
wlr_box finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.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}; m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox; return finalBox;
} }
wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() { CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
@@ -113,7 +110,7 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
POS = PMONITOR->vecPosition; POS = PMONITOR->vecPosition;
SIZE = PMONITOR->vecSize; 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)) { if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
@@ -131,10 +128,10 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
SIZE.y += PMONITOR->vecReservedBottomRight.y; 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(); const int BORDERSIZE = getRealBorderSize();
if (m_sAdditionalConfigData.dimAround) { if (m_sAdditionalConfigData.dimAround) {
@@ -144,12 +141,7 @@ wlr_box CWindow::getWindowInputBox() {
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; 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;
const auto EXTENTS = wd->getWindowDecorationExtents();
if (EXTENTS.topLeft.x > maxExtents.topLeft.x) if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x; maxExtents.topLeft.x = EXTENTS.topLeft.x;
@@ -162,40 +154,32 @@ wlr_box CWindow::getWindowInputBox() {
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y) if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y; maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
}
// Add extents to the real base BB and return // 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, 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}; m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox; 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 CWindow::getFullWindowReservedArea() {
SWindowDecorationExtents extents; return g_pDecorationPositioner->getWindowDecorationReserved(this);
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;
} }
void CWindow::updateWindowDecos() { void CWindow::updateWindowDecos() {
for (auto& wd : m_dWindowDecorations)
wd->updateWindow(this);
bool recalc = false; bool recalc = false;
if (!m_bIsMapped || isHidden())
return;
for (auto& wd : m_vDecosToRemove) { for (auto& wd : m_vDecosToRemove) {
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) { for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
if (it->get() == wd) { if (it->get() == wd) {
g_pDecorationPositioner->uncacheDecoration(it->get());
it = m_dWindowDecorations.erase(it); it = m_dWindowDecorations.erase(it);
recalc = true; recalc = true;
if (it == m_dWindowDecorations.end()) if (it == m_dWindowDecorations.end())
@@ -204,10 +188,26 @@ void CWindow::updateWindowDecos() {
} }
} }
g_pDecorationPositioner->onWindowUpdate(this);
if (recalc) if (recalc)
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this); g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
m_vDecosToRemove.clear(); 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));
updateWindowDecos();
}
void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
m_vDecosToRemove.push_back(deco);
updateWindowDecos();
} }
pid_t CWindow::getPID() { pid_t CWindow::getPID() {
@@ -219,6 +219,9 @@ pid_t CWindow::getPID() {
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr); wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
} else { } else {
if (!m_bIsMapped || !m_bMappedX11)
return -1;
PID = m_uSurface.xwayland->pid; PID = m_uSurface.xwayland->pid;
} }
@@ -325,7 +328,8 @@ void CWindow::updateSurfaceOutputs() {
m_pWLSurface.wlr(), m_pWLSurface.wlr(),
[](wlr_surface* surf, int x, int y, void* data) { [](wlr_surface* surf, int x, int y, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID); 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); this);
} }
@@ -334,6 +338,10 @@ void CWindow::moveToWorkspace(int workspaceID) {
if (m_iWorkspaceID == workspaceID) if (m_iWorkspaceID == workspaceID)
return; return;
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
const int OLDWORKSPACE = m_iWorkspaceID;
m_iWorkspaceID = workspaceID; m_iWorkspaceID = workspaceID;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
@@ -352,6 +360,15 @@ void CWindow::moveToWorkspace(int workspaceID) {
// update xwayland coords // update xwayland coords
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec()); 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() { CWindow* CWindow::X11TransientFor() {
@@ -414,11 +431,17 @@ void CWindow::onUnmap() {
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID) if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient == this)
PMONITOR->solitaryClient = nullptr;
} }
void CWindow::onMap() { void CWindow::onMap() {
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this)); 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) // JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
m_vRealPosition.resetAllCallbacks(); m_vRealPosition.resetAllCallbacks();
@@ -448,6 +471,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, hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->surface->events.unmap : &m_uSurface.xdg->surface->events.unmap, &Events::listener_unmapWindow, this,
"CWindow"); "CWindow");
m_vReportedSize = m_vPendingReportedSize;
} }
void CWindow::onBorderAngleAnimEnd(void* ptr) { void CWindow::onBorderAngleAnimEnd(void* ptr) {
@@ -492,15 +517,19 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} else if (r.szRule == "opaque") { } else if (r.szRule == "opaque") {
if (!m_sAdditionalConfigData.forceOpaqueOverridden) if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = true; 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 { try {
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.find("bordersize") == 0) { } else if (r.szRule.starts_with("bordersize")) {
try { try {
m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.find("opacity") == 0) { } else if (r.szRule.starts_with("opacity")) {
try { try {
CVarList vars(r.szRule, 0, ' '); CVarList vars(r.szRule, 0, ' ');
@@ -533,10 +562,10 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "noanim") { } else if (r.szRule == "noanim") {
m_sAdditionalConfigData.forceNoAnims = true; 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); auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sAdditionalConfigData.animationStyle = STYLE; m_sAdditionalConfigData.animationStyle = STYLE;
} else if (r.szRule.find("bordercolor") == 0) { } else if (r.szRule.starts_with("bordercolor")) {
try { try {
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
@@ -552,7 +581,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
m_sAdditionalConfigData.dimAround = true; m_sAdditionalConfigData.dimAround = true;
} else if (r.szRule == "keepaspectratio") { } else if (r.szRule == "keepaspectratio") {
m_sAdditionalConfigData.keepAspectRatio = true; m_sAdditionalConfigData.keepAspectRatio = true;
} else if (r.szRule.find("xray") == 0) { } else if (r.szRule.starts_with("xray")) {
CVarList vars(r.szRule, 0, ' '); CVarList vars(r.szRule, 0, ' ');
try { try {
@@ -580,6 +609,8 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.borderSize = -1; m_sAdditionalConfigData.borderSize = -1;
m_sAdditionalConfigData.keepAspectRatio = false; m_sAdditionalConfigData.keepAspectRatio = false;
m_sAdditionalConfigData.xray = -1; m_sAdditionalConfigData.xray = -1;
m_sAdditionalConfigData.forceTearing = false;
m_sAdditionalConfigData.nearestNeighbor = false;
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this); const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
for (auto& r : WINDOWRULES) { for (auto& r : WINDOWRULES) {
@@ -622,9 +653,9 @@ bool CWindow::isInCurvedCorner(double x, double y) {
void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) { void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) {
const auto DATA = (SExtensionFindingData*)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; *DATA->found = surface;
} }
@@ -654,14 +685,14 @@ void CWindow::createGroup() {
Debug::log(LOG, "createGroup: window:{:x},title:{} is denied as a group, ignored", (uintptr_t)this, this->m_szTitle); Debug::log(LOG, "createGroup: window:{:x},title:{} is denied as a group, ignored", (uintptr_t)this, this->m_szTitle);
return; return;
} }
if (!m_sGroupData.pNextWindow) { if (!m_sGroupData.pNextWindow) {
m_sGroupData.pNextWindow = this; m_sGroupData.pNextWindow = this;
m_sGroupData.head = true; m_sGroupData.head = true;
m_sGroupData.locked = false; m_sGroupData.locked = false;
m_sGroupData.deny = false; m_sGroupData.deny = false;
m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(this)); addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(this));
updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this); g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -735,6 +766,15 @@ int CWindow::getGroupSize() {
return 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) { CWindow* CWindow::getGroupWindowByIndex(int index) {
const int SIZE = getGroupSize(); const int SIZE = getGroupSize();
index = ((index % SIZE) + SIZE) % SIZE; index = ((index % SIZE) + SIZE) % SIZE;
@@ -791,6 +831,8 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode); g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode);
g_pHyprRenderer->damageWindow(pWindow); g_pHyprRenderer->damageWindow(pWindow);
pWindow->updateWindowDecos();
} }
void CWindow::insertWindowToGroup(CWindow* pWindow) { void CWindow::insertWindowToGroup(CWindow* pWindow) {
@@ -798,7 +840,7 @@ void CWindow::insertWindowToGroup(CWindow* pWindow) {
const auto ENDAT = m_sGroupData.pNextWindow; const auto ENDAT = m_sGroupData.pNextWindow;
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow)); pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
if (!pWindow->m_sGroupData.pNextWindow) { if (!pWindow->m_sGroupData.pNextWindow) {
BEGINAT->m_sGroupData.pNextWindow = pWindow; BEGINAT->m_sGroupData.pNextWindow = pWindow;
@@ -874,6 +916,9 @@ bool CWindow::opaque() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); 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) if (PWORKSPACE->m_fAlpha.fl() != 1.f)
return false; return false;
@@ -925,3 +970,7 @@ int CWindow::getRealBorderSize() {
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
} }
bool CWindow::canBeTorn() {
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
}

View File

@@ -11,14 +11,16 @@
#include "macros.hpp" #include "macros.hpp"
#include "managers/XWaylandManager.hpp" #include "managers/XWaylandManager.hpp"
enum eIdleInhibitMode { enum eIdleInhibitMode
{
IDLEINHIBIT_NONE = 0, IDLEINHIBIT_NONE = 0,
IDLEINHIBIT_ALWAYS, IDLEINHIBIT_ALWAYS,
IDLEINHIBIT_FULLSCREEN, IDLEINHIBIT_FULLSCREEN,
IDLEINHIBIT_FOCUS IDLEINHIBIT_FOCUS
}; };
enum eGroupRules { enum eGroupRules
{
// effective only during first map, except for _ALWAYS variant // effective only during first map, except for _ALWAYS variant
GROUP_NONE = 0, GROUP_NONE = 0,
GROUP_SET = 1 << 0, // Open as new group or add to focused group GROUP_SET = 1 << 0, // Open as new group or add to focused group
@@ -30,6 +32,8 @@ enum eGroupRules {
GROUP_OVERRIDE = 1 << 6, // Override other rules GROUP_OVERRIDE = 1 << 6, // Override other rules
}; };
class IWindowTransformer;
template <typename T> template <typename T>
class CWindowOverridableVar { class CWindowOverridableVar {
public: public:
@@ -138,6 +142,8 @@ struct SWindowAdditionalConfigData {
CWindowOverridableVar<bool> keepAspectRatio = false; CWindowOverridableVar<bool> keepAspectRatio = false;
CWindowOverridableVar<int> xray = -1; // -1 means unset, takes precedence over the renderdata one 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<int> borderSize = -1; // -1 means unset, takes precedence over the renderdata one
CWindowOverridableVar<bool> forceTearing = false;
CWindowOverridableVar<bool> nearestNeighbor = false;
}; };
struct SWindowRule { struct SWindowRule {
@@ -179,6 +185,7 @@ class CWindow {
DYNLISTENER(setOverrideRedirect); DYNLISTENER(setOverrideRedirect);
DYNLISTENER(associateX11); DYNLISTENER(associateX11);
DYNLISTENER(dissociateX11); DYNLISTENER(dissociateX11);
DYNLISTENER(ackConfigure);
// DYNLISTENER(newSubsurfaceWindow); // DYNLISTENER(newSubsurfaceWindow);
CWLSurface m_pWLSurface; CWLSurface m_pWLSurface;
@@ -200,6 +207,9 @@ class CWindow {
// for not spamming the protocols // for not spamming the protocols
Vector2D m_vReportedPosition; Vector2D m_vReportedPosition;
Vector2D m_vReportedSize; 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 // for restoring floating statuses
Vector2D m_vLastFloatingSize; Vector2D m_vLastFloatingSize;
@@ -286,6 +296,9 @@ class CWindow {
SWindowSpecialRenderData m_sSpecialRenderData; SWindowSpecialRenderData m_sSpecialRenderData;
SWindowAdditionalConfigData m_sAdditionalConfigData; SWindowAdditionalConfigData m_sAdditionalConfigData;
// Transformers
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
// for alpha // for alpha
CAnimatedVariable m_fActiveInactiveAlpha; CAnimatedVariable m_fActiveInactiveAlpha;
@@ -317,6 +330,8 @@ class CWindow {
} m_sGroupData; } m_sGroupData;
uint16_t m_eGroupRules = GROUP_NONE; uint16_t m_eGroupRules = GROUP_NONE;
bool m_bTearingHint = false;
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) { bool operator==(const CWindow& rhs) {
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
@@ -324,11 +339,14 @@ class CWindow {
} }
// methods // methods
wlr_box getFullWindowBoundingBox(); CBox getFullWindowBoundingBox();
SWindowDecorationExtents getFullWindowExtents(); SWindowDecorationExtents getFullWindowExtents();
wlr_box getWindowInputBox(); CBox getWindowInputBox();
wlr_box getWindowIdealBoundingBoxIgnoreReserved(); CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos(); void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco);
pid_t getPID(); pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType); IHyprWindowDecoration* getDecorationByType(eDecorationType);
void removeDecorationByType(eDecorationType); void removeDecorationByType(eDecorationType);
@@ -348,6 +366,7 @@ class CWindow {
Vector2D middle(); Vector2D middle();
bool opaque(); bool opaque();
float rounding(); float rounding();
bool canBeTorn();
int getRealBorderSize(); int getRealBorderSize();
void updateSpecialRenderData(); void updateSpecialRenderData();
@@ -365,6 +384,7 @@ class CWindow {
CWindow* getGroupPrevious(); CWindow* getGroupPrevious();
CWindow* getGroupWindowByIndex(int); CWindow* getGroupWindowByIndex(int);
int getGroupSize(); int getGroupSize();
bool canBeGroupedInto(CWindow* pWindow);
void setGroupCurrent(CWindow* pWindow); void setGroupCurrent(CWindow* pWindow);
void insertWindowToGroup(CWindow* pWindow); void insertWindowToGroup(CWindow* pWindow);
void updateGroupOutputs(); void updateGroupOutputs();

View File

@@ -2,6 +2,7 @@
#include "../managers/KeybindManager.hpp" #include "../managers/KeybindManager.hpp"
#include <string.h> #include <string.h>
#include <string>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
@@ -19,10 +20,16 @@ CConfigManager::CConfigManager() {
configValues["general:col.inactive_border"].data = std::make_shared<CGradientValueData>(0xff444444); configValues["general:col.inactive_border"].data = std::make_shared<CGradientValueData>(0xff444444);
configValues["general:col.nogroup_border"].data = std::make_shared<CGradientValueData>(0xffffaaff); configValues["general:col.nogroup_border"].data = std::make_shared<CGradientValueData>(0xffffaaff);
configValues["general:col.nogroup_border_active"].data = std::make_shared<CGradientValueData>(0xffff00ff); configValues["general:col.nogroup_border_active"].data = std::make_shared<CGradientValueData>(0xffff00ff);
configValues["general:col.group_border"].data = std::make_shared<CGradientValueData>(0x66777700);
configValues["general:col.group_border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00); configValues["group:col.border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
configValues["general:col.group_border_locked"].data = std::make_shared<CGradientValueData>(0x66775500); configValues["group:col.border_inactive"].data = std::make_shared<CGradientValueData>(0x66777700);
configValues["general:col.group_border_locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500); configValues["group:col.border_locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500);
configValues["group:col.border_locked_inactive"].data = std::make_shared<CGradientValueData>(0x66775500);
configValues["group:groupbar:col.active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
configValues["group:groupbar:col.inactive"].data = std::make_shared<CGradientValueData>(0x66777700);
configValues["group:groupbar:col.locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500);
configValues["group:groupbar:col.locked_inactive"].data = std::make_shared<CGradientValueData>(0x66775500);
setDefaultVars(); setDefaultVars();
setDefaultAnimationVars(); setDefaultAnimationVars();
@@ -76,10 +83,6 @@ void CConfigManager::setDefaultVars() {
((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444); ((CGradientValueData*)configValues["general:col.inactive_border"].data.get())->reset(0xff444444);
((CGradientValueData*)configValues["general:col.nogroup_border"].data.get())->reset(0xff444444); ((CGradientValueData*)configValues["general:col.nogroup_border"].data.get())->reset(0xff444444);
((CGradientValueData*)configValues["general:col.nogroup_border_active"].data.get())->reset(0xffff00ff); ((CGradientValueData*)configValues["general:col.nogroup_border_active"].data.get())->reset(0xffff00ff);
((CGradientValueData*)configValues["general:col.group_border"].data.get())->reset(0x66777700);
((CGradientValueData*)configValues["general:col.group_border_active"].data.get())->reset(0x66ffff00);
((CGradientValueData*)configValues["general:col.group_border_locked"].data.get())->reset(0x66775500);
((CGradientValueData*)configValues["general:col.group_border_locked_active"].data.get())->reset(0x66ff5500);
configValues["general:cursor_inactive_timeout"].intValue = 0; configValues["general:cursor_inactive_timeout"].intValue = 0;
configValues["general:no_cursor_warps"].intValue = 0; configValues["general:no_cursor_warps"].intValue = 0;
configValues["general:no_focus_fallback"].intValue = 0; configValues["general:no_focus_fallback"].intValue = 0;
@@ -87,11 +90,12 @@ void CConfigManager::setDefaultVars() {
configValues["general:extend_border_grab_area"].intValue = 15; configValues["general:extend_border_grab_area"].intValue = 15;
configValues["general:hover_icon_on_border"].intValue = 1; configValues["general:hover_icon_on_border"].intValue = 1;
configValues["general:layout"].strValue = "dwindle"; configValues["general:layout"].strValue = "dwindle";
configValues["general:allow_tearing"].intValue = 0;
configValues["misc:disable_hyprland_logo"].intValue = 0; configValues["misc:disable_hyprland_logo"].intValue = 0;
configValues["misc:disable_splash_rendering"].intValue = 0; configValues["misc:disable_splash_rendering"].intValue = 0;
configValues["misc:disable_hypr_chan"].intValue = 0;
configValues["misc:force_hypr_chan"].intValue = 0; configValues["misc:force_hypr_chan"].intValue = 0;
configValues["misc:force_default_wallpaper"].intValue = -1;
configValues["misc:vfr"].intValue = 1; configValues["misc:vfr"].intValue = 1;
configValues["misc:vrr"].intValue = 0; configValues["misc:vrr"].intValue = 0;
configValues["misc:mouse_move_enables_dpms"].intValue = 0; configValues["misc:mouse_move_enables_dpms"].intValue = 0;
@@ -113,15 +117,29 @@ void CConfigManager::setDefaultVars() {
configValues["misc:cursor_zoom_factor"].floatValue = 1.f; configValues["misc:cursor_zoom_factor"].floatValue = 1.f;
configValues["misc:cursor_zoom_rigid"].intValue = 0; configValues["misc:cursor_zoom_rigid"].intValue = 0;
configValues["misc:allow_session_lock_restore"].intValue = 0; configValues["misc:allow_session_lock_restore"].intValue = 0;
configValues["misc:groupbar_scrolling"].intValue = 1;
configValues["misc:group_insert_after_current"].intValue = 1;
configValues["misc:group_focus_removed_window"].intValue = 1;
configValues["misc:render_titles_in_groupbar"].intValue = 1;
configValues["misc:groupbar_titles_font_size"].intValue = 8;
configValues["misc:groupbar_gradients"].intValue = 1;
configValues["misc:close_special_on_empty"].intValue = 1; configValues["misc:close_special_on_empty"].intValue = 1;
configValues["misc:groupbar_text_color"].intValue = 0xffffffff;
configValues["misc:background_color"].intValue = 0xff111111; configValues["misc:background_color"].intValue = 0xff111111;
configValues["misc:new_window_takes_over_fullscreen"].intValue = 0;
((CGradientValueData*)configValues["group:col.border_active"].data.get())->reset(0x66ffff00);
((CGradientValueData*)configValues["group:col.border_inactive"].data.get())->reset(0x66777700);
((CGradientValueData*)configValues["group:col.border_locked_active"].data.get())->reset(0x66ff5500);
((CGradientValueData*)configValues["group:col.border_locked_inactive"].data.get())->reset(0x66775500);
configValues["group:insert_after_current"].intValue = 1;
configValues["group:focus_removed_window"].intValue = 1;
configValues["group:groupbar:font_family"].strValue = "Sans";
configValues["group:groupbar:font_size"].intValue = 8;
configValues["group:groupbar:gradients"].intValue = 1;
configValues["group:groupbar:render_titles"].intValue = 1;
configValues["group:groupbar:scrolling"].intValue = 1;
configValues["group:groupbar:text_color"].intValue = 0xffffffff;
((CGradientValueData*)configValues["group:groupbar:col.active"].data.get())->reset(0x66ffff00);
((CGradientValueData*)configValues["group:groupbar:col.inactive"].data.get())->reset(0x66777700);
((CGradientValueData*)configValues["group:groupbar:col.locked_active"].data.get())->reset(0x66ff5500);
((CGradientValueData*)configValues["group:groupbar:col.locked_inactive"].data.get())->reset(0x66775500);
configValues["debug:int"].intValue = 0; configValues["debug:int"].intValue = 0;
configValues["debug:log_damage"].intValue = 0; configValues["debug:log_damage"].intValue = 0;
@@ -133,6 +151,7 @@ void CConfigManager::setDefaultVars() {
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL; configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
configValues["debug:manual_crash"].intValue = 0; configValues["debug:manual_crash"].intValue = 0;
configValues["debug:suppress_errors"].intValue = 0; configValues["debug:suppress_errors"].intValue = 0;
configValues["debug:watchdog_timeout"].intValue = 5;
configValues["decoration:rounding"].intValue = 0; configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur:enabled"].intValue = 1; configValues["decoration:blur:enabled"].intValue = 1;
@@ -141,14 +160,15 @@ void CConfigManager::setDefaultVars() {
configValues["decoration:blur:ignore_opacity"].intValue = 0; configValues["decoration:blur:ignore_opacity"].intValue = 0;
configValues["decoration:blur:new_optimizations"].intValue = 1; configValues["decoration:blur:new_optimizations"].intValue = 1;
configValues["decoration:blur:xray"].intValue = 0; configValues["decoration:blur:xray"].intValue = 0;
configValues["decoration:blur:noise"].floatValue = 0.0117;
configValues["decoration:blur:contrast"].floatValue = 0.8916; configValues["decoration:blur:contrast"].floatValue = 0.8916;
configValues["decoration:blur:brightness"].floatValue = 0.8172; configValues["decoration:blur:brightness"].floatValue = 1.0;
configValues["decoration:blur:vibrancy"].floatValue = 0.1696;
configValues["decoration:blur:vibrancy_darkness"].floatValue = 0.0;
configValues["decoration:blur:noise"].floatValue = 0.0117;
configValues["decoration:blur:special"].intValue = 0; configValues["decoration:blur:special"].intValue = 0;
configValues["decoration:active_opacity"].floatValue = 1; configValues["decoration:active_opacity"].floatValue = 1;
configValues["decoration:inactive_opacity"].floatValue = 1; configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 1; configValues["decoration:fullscreen_opacity"].floatValue = 1;
configValues["decoration:multisample_edges"].intValue = 1;
configValues["decoration:no_blur_on_oversized"].intValue = 0; configValues["decoration:no_blur_on_oversized"].intValue = 0;
configValues["decoration:drop_shadow"].intValue = 1; configValues["decoration:drop_shadow"].intValue = 1;
configValues["decoration:shadow_range"].intValue = 4; configValues["decoration:shadow_range"].intValue = 4;
@@ -186,6 +206,7 @@ void CConfigManager::setDefaultVars() {
configValues["master:inherit_fullscreen"].intValue = 1; configValues["master:inherit_fullscreen"].intValue = 1;
configValues["master:allow_small_split"].intValue = 0; configValues["master:allow_small_split"].intValue = 0;
configValues["master:smart_resizing"].intValue = 1; configValues["master:smart_resizing"].intValue = 1;
configValues["master:drop_at_cursor"].intValue = 1;
configValues["animations:enabled"].intValue = 1; configValues["animations:enabled"].intValue = 1;
@@ -222,13 +243,17 @@ void CConfigManager::setDefaultVars() {
configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY; configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY;
configValues["input:tablet:transform"].intValue = 0; configValues["input:tablet:transform"].intValue = 0;
configValues["input:tablet:output"].strValue = STRVAL_EMPTY; configValues["input:tablet:output"].strValue = STRVAL_EMPTY;
configValues["input:tablet:region_position"].vecValue = Vector2D();
configValues["input:tablet:region_size"].vecValue = Vector2D();
configValues["binds:pass_mouse_when_bound"].intValue = 0; configValues["binds:pass_mouse_when_bound"].intValue = 0;
configValues["binds:scroll_event_delay"].intValue = 300; configValues["binds:scroll_event_delay"].intValue = 300;
configValues["binds:workspace_back_and_forth"].intValue = 0; configValues["binds:workspace_back_and_forth"].intValue = 0;
configValues["binds:allow_workspace_cycles"].intValue = 0; configValues["binds:allow_workspace_cycles"].intValue = 0;
configValues["binds:workspace_center_on"].intValue = 1;
configValues["binds:focus_preferred_method"].intValue = 0; configValues["binds:focus_preferred_method"].intValue = 0;
configValues["binds:ignore_group_lock"].intValue = 0; configValues["binds:ignore_group_lock"].intValue = 0;
configValues["binds:movefocus_cycles_fullscreen"].intValue = 1;
configValues["gestures:workspace_swipe"].intValue = 0; configValues["gestures:workspace_swipe"].intValue = 0;
configValues["gestures:workspace_swipe_fingers"].intValue = 3; configValues["gestures:workspace_swipe_fingers"].intValue = 3;
@@ -278,6 +303,8 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
cfgValues["transform"].intValue = 0; cfgValues["transform"].intValue = 0;
cfgValues["output"].strValue = STRVAL_EMPTY; cfgValues["output"].strValue = STRVAL_EMPTY;
cfgValues["enabled"].intValue = 1; // only for mice / touchpads cfgValues["enabled"].intValue = 1; // only for mice / touchpads
cfgValues["region_position"].vecValue = Vector2D(); // only for tablets
cfgValues["region_size"].vecValue = Vector2D(); // only for tablets
} }
void CConfigManager::setDefaultAnimationVars() { void CConfigManager::setDefaultAnimationVars() {
@@ -347,8 +374,8 @@ void CConfigManager::init() {
} }
void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) { void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) {
if (configValues.find(COMMAND) == configValues.end()) { if (!configValues.contains(COMMAND)) {
if (COMMAND.find("device:") != 0 /* devices parsed later */ && COMMAND.find("plugin:") != 0 /* plugins parsed later */) { if (!COMMAND.starts_with("device:") /* devices parsed later */ && !COMMAND.starts_with("plugin:") /* plugins parsed later */) {
if (COMMAND[0] == '$') { if (COMMAND[0] == '$') {
// register a dynamic var // register a dynamic var
Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE); Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE);
@@ -365,7 +392,7 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
SConfigValue* CONFIGENTRY = nullptr; SConfigValue* CONFIGENTRY = nullptr;
if (COMMAND.find("device:") == 0) { if (COMMAND.starts_with("device:")) {
const auto DEVICE = COMMAND.substr(7).substr(0, COMMAND.find_last_of(':') - 7); const auto DEVICE = COMMAND.substr(7).substr(0, COMMAND.find_last_of(':') - 7);
const auto CONFIGVAR = COMMAND.substr(COMMAND.find_last_of(':') + 1); const auto CONFIGVAR = COMMAND.substr(COMMAND.find_last_of(':') + 1);
@@ -385,7 +412,7 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
} }
CONFIGENTRY = &it->second.at(CONFIGVAR); CONFIGENTRY = &it->second.at(CONFIGVAR);
} else if (COMMAND.find("plugin:") == 0) { } else if (COMMAND.starts_with("plugin:")) {
for (auto& [handle, pMap] : pluginConfigs) { for (auto& [handle, pMap] : pluginConfigs) {
auto it = std::find_if(pMap->begin(), pMap->end(), [&](const auto& other) { return other.first == COMMAND; }); auto it = std::find_if(pMap->begin(), pMap->end(), [&](const auto& other) { return other.first == COMMAND; });
if (it == pMap->end()) { if (it == pMap->end()) {
@@ -623,11 +650,11 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
return; return;
} }
if (ARGS[1].find("pref") == 0) { if (ARGS[1].starts_with("pref")) {
newrule.resolution = Vector2D(); newrule.resolution = Vector2D();
} else if (ARGS[1].find("highrr") == 0) { } else if (ARGS[1].starts_with("highrr")) {
newrule.resolution = Vector2D(-1, -1); newrule.resolution = Vector2D(-1, -1);
} else if (ARGS[1].find("highres") == 0) { } else if (ARGS[1].starts_with("highres")) {
newrule.resolution = Vector2D(-1, -2); newrule.resolution = Vector2D(-1, -2);
} else if (parseModeLine(ARGS[1], newrule.drmMode)) { } else if (parseModeLine(ARGS[1], newrule.drmMode)) {
newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay); newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay);
@@ -640,14 +667,14 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
newrule.refreshRate = stof(ARGS[1].substr(ARGS[1].find_first_of('@') + 1)); newrule.refreshRate = stof(ARGS[1].substr(ARGS[1].find_first_of('@') + 1));
} }
if (ARGS[2].find("auto") == 0) { if (ARGS[2].starts_with("auto")) {
newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX); newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX);
} else { } else {
newrule.offset.x = stoi(ARGS[2].substr(0, ARGS[2].find_first_of('x'))); newrule.offset.x = stoi(ARGS[2].substr(0, ARGS[2].find_first_of('x')));
newrule.offset.y = stoi(ARGS[2].substr(ARGS[2].find_first_of('x') + 1)); newrule.offset.y = stoi(ARGS[2].substr(ARGS[2].find_first_of('x') + 1));
} }
if (ARGS[3].find("auto") == 0) { if (ARGS[3].starts_with("auto")) {
newrule.scale = -1; newrule.scale = -1;
} else { } else {
newrule.scale = stof(ARGS[3]); newrule.scale = stof(ARGS[3]);
@@ -810,6 +837,7 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
bool mouse = false; bool mouse = false;
bool nonConsuming = false; bool nonConsuming = false;
bool transparent = false; bool transparent = false;
bool ignoreMods = false;
const auto BINDARGS = command.substr(4); const auto BINDARGS = command.substr(4);
for (auto& arg : BINDARGS) { for (auto& arg : BINDARGS) {
@@ -825,6 +853,8 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
nonConsuming = true; nonConsuming = true;
} else if (arg == 't') { } else if (arg == 't') {
transparent = true; transparent = true;
} else if (arg == 'i') {
ignoreMods = true;
} else { } else {
parseError = "bind: invalid flag"; parseError = "bind: invalid flag";
return; return;
@@ -882,12 +912,13 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
if (KEY != "") { if (KEY != "") {
if (isNumber(KEY) && std::stoi(KEY) > 9) if (isNumber(KEY) && std::stoi(KEY) > 9)
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent});
else if (KEY.find("code:") == 0 && isNumber(KEY.substr(5)))
g_pKeybindManager->addKeybind( g_pKeybindManager->addKeybind(
SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent}); SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
else if (KEY.starts_with("code:") && isNumber(KEY.substr(5)))
g_pKeybindManager->addKeybind(
SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
else else
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent}); g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
} }
} }
@@ -902,17 +933,17 @@ void CConfigManager::handleUnbind(const std::string& command, const std::string&
} }
bool windowRuleValid(const std::string& RULE) { bool windowRuleValid(const std::string& RULE) {
return !(RULE != "float" && RULE != "tile" && RULE.find("opacity") != 0 && RULE.find("move") != 0 && RULE.find("size") != 0 && RULE.find("minsize") != 0 && return RULE == "float" || RULE == "tile" || RULE.starts_with("opacity") || RULE.starts_with("move") || RULE.starts_with("size") || RULE.starts_with("minsize") ||
RULE.find("maxsize") != 0 && RULE.find("pseudo") != 0 && RULE.find("monitor") != 0 && RULE.find("idleinhibit") != 0 && RULE != "nofocus" && RULE != "noblur" && RULE.starts_with("maxsize") || RULE.starts_with("pseudo") || RULE.starts_with("monitor") || RULE.starts_with("idleinhibit") || RULE == "nofocus" || RULE == "noblur" ||
RULE != "noshadow" && RULE != "nodim" && RULE != "noborder" && RULE != "opaque" && RULE != "forceinput" && RULE != "fullscreen" && RULE != "nofullscreenrequest" && RULE == "noshadow" || RULE == "nodim" || RULE == "noborder" || RULE == "opaque" || RULE == "forceinput" || RULE == "fullscreen" || RULE == "nofullscreenrequest" ||
RULE != "nomaximizerequest" && RULE != "fakefullscreen" && RULE != "nomaxsize" && RULE != "pin" && RULE != "noanim" && RULE != "dimaround" && RULE != "windowdance" && RULE == "nomaximizerequest" || RULE == "fakefullscreen" || RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" ||
RULE != "maximize" && RULE != "keepaspectratio" && RULE.find("animation") != 0 && RULE.find("rounding") != 0 && RULE.find("workspace") != 0 && RULE == "maximize" || RULE == "keepaspectratio" || RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") ||
RULE.find("bordercolor") != 0 && RULE != "forcergbx" && RULE != "noinitialfocus" && RULE != "stayfocused" && RULE.find("bordersize") != 0 && RULE.find("xray") != 0 && RULE.starts_with("bordercolor") || RULE == "forcergbx" || RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") ||
RULE.find("center") != 0 && RULE.find("group") != 0); RULE.starts_with("center") || RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor";
} }
bool layerRuleValid(const std::string& RULE) { bool layerRuleValid(const std::string& RULE) {
return !(RULE != "noanim" && RULE != "blur" && RULE.find("ignorealpha") != 0 && RULE.find("ignorezero") != 0 && RULE.find("xray") != 0); return RULE == "noanim" || RULE == "blur" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE.starts_with("xray");
} }
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) { void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
@@ -936,7 +967,7 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
return; return;
} }
if (RULE.find("size") == 0 || RULE.find("maxsize") == 0 || RULE.find("minsize") == 0) if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
m_dWindowRules.push_front({RULE, VALUE}); m_dWindowRules.push_front({RULE, VALUE});
else else
m_dWindowRules.push_back({RULE, VALUE}); m_dWindowRules.push_back({RULE, VALUE});
@@ -970,7 +1001,7 @@ void CConfigManager::handleLayerRule(const std::string& command, const std::stri
} }
void CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) { void CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) {
const auto RULE = value.substr(0, value.find_first_of(',')); const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
const auto VALUE = value.substr(value.find_first_of(',') + 1); const auto VALUE = value.substr(value.find_first_of(',') + 1);
if (!windowRuleValid(RULE) && RULE != "unset") { if (!windowRuleValid(RULE) && RULE != "unset") {
@@ -1083,14 +1114,14 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
return; return;
} }
if (RULE.find("size") == 0 || RULE.find("maxsize") == 0 || RULE.find("minsize") == 0) if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
m_dWindowRules.push_front(rule); m_dWindowRules.push_front(rule);
else else
m_dWindowRules.push_back(rule); m_dWindowRules.push_back(rule);
} }
void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBlur) { void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBlur) {
const bool BYADDRESS = name.find("address:") == 0; const bool BYADDRESS = name.starts_with("address:");
std::string matchName = name; std::string matchName = name;
if (BYADDRESS) { if (BYADDRESS) {
@@ -1111,7 +1142,7 @@ void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBl
} }
void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) { void CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
if (value.find("remove,") == 0) { if (value.starts_with("remove,")) {
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7)); const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; })) if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; }))
updateBlurredLS(TOREMOVE, false); updateBlurredLS(TOREMOVE, false);
@@ -1150,6 +1181,9 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
rules = value.substr(WORKSPACE_DELIM + 1); rules = value.substr(WORKSPACE_DELIM + 1);
} }
const static std::string ruleOnCreatedEmtpy = "on-created-empty:";
const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length();
auto assignRule = [&](std::string rule) { auto assignRule = [&](std::string rule) {
size_t delim = std::string::npos; size_t delim = std::string::npos;
if ((delim = rule.find("gapsin:")) != std::string::npos) if ((delim = rule.find("gapsin:")) != std::string::npos)
@@ -1170,6 +1204,10 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
wsRule.monitor = rule.substr(delim + 8); wsRule.monitor = rule.substr(delim + 8);
else if ((delim = rule.find("default:")) != std::string::npos) else if ((delim = rule.find("default:")) != std::string::npos)
wsRule.isDefault = configStringToInt(rule.substr(delim + 8)); wsRule.isDefault = configStringToInt(rule.substr(delim + 8));
else if ((delim = rule.find("persistent:")) != std::string::npos)
wsRule.isPersistent = configStringToInt(rule.substr(delim + 11));
else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos)
wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen));
}; };
size_t pos = 0; size_t pos = 0;
@@ -1239,6 +1277,8 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
std::string line = ""; std::string line = "";
int linenum = 1; int linenum = 1;
if (ifs.is_open()) { if (ifs.is_open()) {
auto configCurrentPathBackup = configCurrentPath;
while (std::getline(ifs, line)) { while (std::getline(ifs, line)) {
// Read line by line. // Read line by line.
try { try {
@@ -1251,7 +1291,7 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
parseError += "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): Line parsing error."; parseError += "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): Line parsing error.";
} }
if (parseError != "" && parseError.find("Config error at line") != 0) { if (parseError != "" && !parseError.starts_with("Config error at line")) {
parseError = "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): " + parseError; parseError = "Config error at line " + std::to_string(linenum) + " (" + configCurrentPath + "): " + parseError;
} }
@@ -1259,6 +1299,8 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
} }
ifs.close(); ifs.close();
configCurrentPath = configCurrentPathBackup;
} }
} }
} }
@@ -1322,7 +1364,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
} }
} else if (COMMAND == "monitor") } else if (COMMAND == "monitor")
handleMonitor(COMMAND, VALUE); handleMonitor(COMMAND, VALUE);
else if (COMMAND.find("bind") == 0) else if (COMMAND.starts_with("bind"))
handleBind(COMMAND, VALUE); handleBind(COMMAND, VALUE);
else if (COMMAND == "unbind") else if (COMMAND == "unbind")
handleUnbind(COMMAND, VALUE); handleUnbind(COMMAND, VALUE);
@@ -1346,14 +1388,21 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
handleBlurLS(COMMAND, VALUE); handleBlurLS(COMMAND, VALUE);
else if (COMMAND == "wsbind") else if (COMMAND == "wsbind")
handleBindWS(COMMAND, VALUE); handleBindWS(COMMAND, VALUE);
else if (COMMAND.find("env") == 0) else if (COMMAND == "plugin")
handleEnv(COMMAND, VALUE);
else if (COMMAND.find("plugin") == 0)
handlePlugin(COMMAND, VALUE); handlePlugin(COMMAND, VALUE);
else if (COMMAND.starts_with("env"))
handleEnv(COMMAND, VALUE);
else { else {
// try config
const auto IT = std::find_if(pluginKeywords.begin(), pluginKeywords.end(), [&](const auto& other) { return other.name == COMMAND; });
if (IT != pluginKeywords.end()) {
IT->fn(COMMAND, VALUE);
} else {
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE); configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
needsLayoutRecalc = 2; needsLayoutRecalc = 2;
} }
}
if (dynamic) { if (dynamic) {
std::string retval = parseError; std::string retval = parseError;
@@ -1361,7 +1410,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
// invalidate layouts if they changed // invalidate layouts if they changed
if (needsLayoutRecalc) { if (needsLayoutRecalc) {
if (needsLayoutRecalc == 1 || COMMAND.contains("gaps_") || COMMAND.find("dwindle:") == 0 || COMMAND.find("master:") == 0) { if (needsLayoutRecalc == 1 || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) {
for (auto& m : g_pCompositor->m_vMonitors) for (auto& m : g_pCompositor->m_vMonitors)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
} }
@@ -1396,7 +1445,7 @@ void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equals
const auto STRAFTERDOLLAR = line.substr(dollarPlace + 1); const auto STRAFTERDOLLAR = line.substr(dollarPlace + 1);
bool found = false; bool found = false;
for (auto& [var, value] : configDynamicVars) { for (auto& [var, value] : configDynamicVars) {
if (STRAFTERDOLLAR.find(var) == 0) { if (STRAFTERDOLLAR.starts_with(var)) {
line.replace(dollarPlace, var.length() + 1, value); line.replace(dollarPlace, var.length() + 1, value);
found = true; found = true;
break; break;
@@ -1406,7 +1455,7 @@ void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equals
if (!found) { if (!found) {
// maybe env? // maybe env?
for (auto& [var, value] : environmentVariables) { for (auto& [var, value] : environmentVariables) {
if (STRAFTERDOLLAR.find(var) == 0) { if (STRAFTERDOLLAR.starts_with(var)) {
line.replace(dollarPlace, var.length() + 1, value); line.replace(dollarPlace, var.length() + 1, value);
break; break;
} }
@@ -1486,6 +1535,8 @@ void CConfigManager::parseLine(std::string& line) {
} }
void CConfigManager::loadConfigLoadVars() { void CConfigManager::loadConfigLoadVars() {
EMIT_HOOK_EVENT("preConfigReload", nullptr);
Debug::log(LOG, "Reloading the config!"); Debug::log(LOG, "Reloading the config!");
parseError = ""; // reset the error parseError = ""; // reset the error
currentCategory = ""; // reset the category currentCategory = ""; // reset the category
@@ -1572,7 +1623,7 @@ void CConfigManager::loadConfigLoadVars() {
parseError += "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): Line parsing error."; parseError += "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): Line parsing error.";
} }
if (parseError != "" && parseError.find("Config error at line") != 0) { if (parseError != "" && !parseError.starts_with("Config error at line")) {
parseError = "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): " + parseError; parseError = "Config error at line " + std::to_string(linenum) + " (" + mainConfigPath + "): " + parseError;
} }
@@ -1733,6 +1784,10 @@ float CConfigManager::getFloat(const std::string& v) {
return getConfigValueSafe(v).floatValue; return getConfigValueSafe(v).floatValue;
} }
Vector2D CConfigManager::getVec(const std::string& v) {
return getConfigValueSafe(v).vecValue;
}
std::string CConfigManager::getString(const std::string& v) { std::string CConfigManager::getString(const std::string& v) {
auto VAL = getConfigValueSafe(v).strValue; auto VAL = getConfigValueSafe(v).strValue;
@@ -1750,6 +1805,10 @@ float CConfigManager::getDeviceFloat(const std::string& dev, const std::string&
return getConfigValueSafeDevice(dev, v, fallback).floatValue; return getConfigValueSafeDevice(dev, v, fallback).floatValue;
} }
Vector2D CConfigManager::getDeviceVec(const std::string& dev, const std::string& v, const std::string& fallback) {
return getConfigValueSafeDevice(dev, v, fallback).vecValue;
}
std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v, const std::string& fallback) { std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v, const std::string& fallback) {
auto VAL = getConfigValueSafeDevice(dev, v, fallback).strValue; auto VAL = getConfigValueSafeDevice(dev, v, fallback).strValue;
@@ -1767,6 +1826,10 @@ void CConfigManager::setFloat(const std::string& v, float val) {
configValues[v].floatValue = val; configValues[v].floatValue = val;
} }
void CConfigManager::setVec(const std::string& v, Vector2D val) {
configValues[v].vecValue = val;
}
void CConfigManager::setString(const std::string& v, const std::string& val) { void CConfigManager::setString(const std::string& v, const std::string& val) {
configValues[v].strValue = val; configValues[v].strValue = val;
} }
@@ -1776,7 +1839,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const std::string& name, const st
for (auto& r : m_dMonitorRules) { for (auto& r : m_dMonitorRules) {
if (r.name == name || if (r.name == name ||
(r.name.find("desc:") == 0 && (r.name.starts_with("desc:") &&
(r.name.substr(5) == displayName || r.name.substr(5) == removeBeginEndSpacesTabs(displayName.substr(0, displayName.find_first_of('(')))))) { (r.name.substr(5) == displayName || r.name.substr(5) == removeBeginEndSpacesTabs(displayName.substr(0, displayName.find_first_of('(')))))) {
found = &r; found = &r;
break; break;
@@ -1804,7 +1867,13 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const std::string& name, const st
} }
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(CWorkspace* pWorkspace) { SWorkspaceRule CConfigManager::getWorkspaceRuleFor(CWorkspace* pWorkspace) {
const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) { return other.workspaceName == pWorkspace->m_szName; }); const auto WORKSPACEIDSTR = std::to_string(pWorkspace->m_iID);
const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) {
return other.workspaceName == pWorkspace->m_szName /* name matches */
|| (pWorkspace->m_bIsSpecialWorkspace && other.workspaceName.starts_with("special:") &&
other.workspaceName.substr(8) == pWorkspace->m_szName) /* special and special:name */
|| (pWorkspace->m_iID > 0 && WORKSPACEIDSTR == other.workspaceName); /* id matches and workspace is numerical */
});
if (IT == m_dWorkspaceRules.end()) if (IT == m_dWorkspaceRules.end())
return SWorkspaceRule{}; return SWorkspaceRule{};
return *IT; return *IT;
@@ -1829,7 +1898,7 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
// check if we have a matching rule // check if we have a matching rule
if (!rule.v2) { if (!rule.v2) {
try { try {
if (rule.szValue.find("title:") == 0) { if (rule.szValue.starts_with("title:")) {
// we have a title rule. // we have a title rule.
std::regex RULECHECK(rule.szValue.substr(6)); std::regex RULECHECK(rule.szValue.substr(6));
@@ -1887,7 +1956,7 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
if (!PWORKSPACE) if (!PWORKSPACE)
continue; continue;
if (rule.szWorkspace.find("name:") == 0) { if (rule.szWorkspace.starts_with("name:")) {
if (PWORKSPACE->m_szName != rule.szWorkspace.substr(5)) if (PWORKSPACE->m_szName != rule.szWorkspace.substr(5))
continue; continue;
} else { } else {
@@ -1945,7 +2014,7 @@ std::vector<SLayerRule> CConfigManager::getMatchingRules(SLayerSurface* pLS) {
return returns; return returns;
for (auto& lr : m_dLayerRules) { for (auto& lr : m_dLayerRules) {
if (lr.targetNamespace.find("address:0x") == 0) { if (lr.targetNamespace.starts_with("address:0x")) {
if (std::format("address:0x{:x}", (uintptr_t)pLS) != lr.targetNamespace) if (std::format("address:0x{:x}", (uintptr_t)pLS) != lr.targetNamespace)
continue; continue;
} else { } else {
@@ -2001,7 +2070,7 @@ void CConfigManager::performMonitorReload() {
bool overAgain = false; bool overAgain = false;
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
if (!m->output) if (!m->output || m->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(m->szName, m->output->description ? m->output->description : ""); auto rule = getMonitorRuleFor(m->szName, m->output->description ? m->output->description : "");
@@ -2020,9 +2089,6 @@ void CConfigManager::performMonitorReload() {
if (overAgain) if (overAgain)
performMonitorReload(); performMonitorReload();
if (!g_pCompositor->m_vMonitors.empty()) // reset unsafe state if we have monitors
g_pCompositor->m_bUnsafeState = false;
m_bWantsMonitorReload = false; m_bWantsMonitorReload = false;
EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr); EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr);
@@ -2070,9 +2136,7 @@ bool CConfigManager::deviceConfigExists(const std::string& dev) {
auto copy = dev; auto copy = dev;
std::replace(copy.begin(), copy.end(), ' ', '-'); std::replace(copy.begin(), copy.end(), ' ', '-');
const auto it = deviceConfigs.find(copy); return deviceConfigs.contains(copy);
return it != deviceConfigs.end();
} }
bool CConfigManager::shouldBlurLS(const std::string& ns) { bool CConfigManager::shouldBlurLS(const std::string& ns) {
@@ -2087,16 +2151,14 @@ bool CConfigManager::shouldBlurLS(const std::string& ns) {
void CConfigManager::ensureMonitorStatus() { void CConfigManager::ensureMonitorStatus() {
for (auto& rm : g_pCompositor->m_vRealMonitors) { for (auto& rm : g_pCompositor->m_vRealMonitors) {
if (!rm->output) if (!rm->output || rm->isUnsafeFallback)
continue; continue;
auto rule = getMonitorRuleFor(rm->szName, rm->output->description ? rm->output->description : ""); auto rule = getMonitorRuleFor(rm->szName, rm->output->description ? rm->output->description : "");
if (rule.disabled == rm->m_bEnabled) { if (rule.disabled == rm->m_bEnabled)
rm->m_pThisWrap = &rm;
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule); g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
} }
}
} }
void CConfigManager::ensureVRR(CMonitor* pMonitor) { void CConfigManager::ensureVRR(CMonitor* pMonitor) {
@@ -2193,7 +2255,7 @@ CMonitor* CConfigManager::getBoundMonitorForWS(const std::string& wsname) {
std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname) { std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname) {
for (auto& wr : m_dWorkspaceRules) { for (auto& wr : m_dWorkspaceRules) {
const auto WSNAME = wr.workspaceName.find("name:") == 0 ? wr.workspaceName.substr(5) : wr.workspaceName; const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName;
if (WSNAME == wsname) { if (WSNAME == wsname) {
return wr.monitor; return wr.monitor;
@@ -2261,8 +2323,13 @@ void CConfigManager::addPluginConfigVar(HANDLE handle, const std::string& name,
} }
} }
void CConfigManager::addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string&, const std::string&)> fn) {
pluginKeywords.emplace_back(SPluginKeyword{handle, name, fn});
}
void CConfigManager::removePluginConfig(HANDLE handle) { void CConfigManager::removePluginConfig(HANDLE handle) {
std::erase_if(pluginConfigs, [&](const auto& other) { return other.first == handle; }); std::erase_if(pluginConfigs, [&](const auto& other) { return other.first == handle; });
std::erase_if(pluginKeywords, [&](const auto& other) { return other.handle == handle; });
} }
std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) { std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) {

View File

@@ -11,6 +11,7 @@
#include <algorithm> #include <algorithm>
#include <regex> #include <regex>
#include <optional> #include <optional>
#include <functional>
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include "../Window.hpp" #include "../Window.hpp"
#include "../helpers/WLClasses.hpp" #include "../helpers/WLClasses.hpp"
@@ -41,6 +42,7 @@ struct SWorkspaceRule {
std::string workspaceName = ""; std::string workspaceName = "";
int workspaceId = -1; int workspaceId = -1;
bool isDefault = false; bool isDefault = false;
bool isPersistent = false;
std::optional<int64_t> gapsIn; std::optional<int64_t> gapsIn;
std::optional<int64_t> gapsOut; std::optional<int64_t> gapsOut;
std::optional<int64_t> borderSize; std::optional<int64_t> borderSize;
@@ -48,6 +50,7 @@ struct SWorkspaceRule {
std::optional<int> rounding; std::optional<int> rounding;
std::optional<int> decorate; std::optional<int> decorate;
std::optional<int> shadow; std::optional<int> shadow;
std::optional<std::string> onCreatedEmptyRunCmd;
}; };
struct SMonitorAdditionalReservedArea { struct SMonitorAdditionalReservedArea {
@@ -69,6 +72,12 @@ struct SAnimationPropertyConfig {
SAnimationPropertyConfig* pParentAnimation = nullptr; SAnimationPropertyConfig* pParentAnimation = nullptr;
}; };
struct SPluginKeyword {
HANDLE handle = 0;
std::string name = "";
std::function<void(const std::string&, const std::string&)> fn;
};
struct SExecRequestedRule { struct SExecRequestedRule {
std::string szRule = ""; std::string szRule = "";
uint64_t iPid = 0; uint64_t iPid = 0;
@@ -83,13 +92,16 @@ class CConfigManager {
int getInt(const std::string&); int getInt(const std::string&);
float getFloat(const std::string&); float getFloat(const std::string&);
Vector2D getVec(const std::string&);
std::string getString(const std::string&); std::string getString(const std::string&);
void setFloat(const std::string&, float); void setFloat(const std::string&, float);
void setInt(const std::string&, int); void setInt(const std::string&, int);
void setVec(const std::string&, Vector2D);
void setString(const std::string&, const std::string&); void setString(const std::string&, const std::string&);
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = ""); int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
float getDeviceFloat(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 = ""); std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
bool deviceConfigExists(const std::string&); bool deviceConfigExists(const std::string&);
bool shouldBlurLS(const std::string&); bool shouldBlurLS(const std::string&);
@@ -115,6 +127,7 @@ class CConfigManager {
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig(); std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value); void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
void addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& cmd, const std::string& val)> fun);
void removePluginConfig(HANDLE handle); void removePluginConfig(HANDLE handle);
// no-op when done. // no-op when done.
@@ -158,6 +171,7 @@ class CConfigManager {
std::vector<std::string> m_vDeclaredPlugins; std::vector<std::string> m_vDeclaredPlugins;
std::unordered_map<HANDLE, std::unique_ptr<std::unordered_map<std::string, SConfigValue>>> pluginConfigs; // stores plugin configs 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 bool isFirstLaunch = true; // For exec-once

View File

@@ -58,6 +58,9 @@ general {
col.inactive_border = rgba(595959aa) col.inactive_border = rgba(595959aa)
layout = dwindle layout = dwindle
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
allow_tearing = false
} }
decoration { decoration {
@@ -108,6 +111,11 @@ gestures {
workspace_swipe = off 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 # Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more # See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
device:epic-mouse-v1 { device:epic-mouse-v1 {
@@ -164,6 +172,10 @@ bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9 bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10 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 # Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1 bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1 bind = $mainMod, mouse_up, workspace, e-1

View File

@@ -1,7 +1,6 @@
#include "CrashReporter.hpp" #include "CrashReporter.hpp"
#include <random> #include <random>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <execinfo.h>
#include <fstream> #include <fstream>
#include <signal.h> #include <signal.h>
@@ -130,7 +129,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
std::ofstream ofs; std::ofstream ofs;
std::string path; std::string path;
if (!CACHE_HOME) { if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) { if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
std::filesystem::create_directory(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); 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"; path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc); ofs.open(path, std::ios::trunc);
} else if (CACHE_HOME) { } else {
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) { if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) {
std::filesystem::create_directory(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); 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"; path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc); ofs.open(path, std::ios::trunc);
} else {
return;
} }
ofs << finalCrashReport; ofs << finalCrashReport;

View File

@@ -63,14 +63,16 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
"transform": {}, "transform": {},
"focused": {}, "focused": {},
"dpmsStatus": {}, "dpmsStatus": {},
"vrr": {} "vrr": {},
"activelyTearing": {}
}},)#", }},)#",
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->output->description ? m->output->description : ""), (m->output->make ? m->output->make : ""), m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->output->description ? m->output->description : ""), (m->output->make ? m->output->make : ""),
(m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate,
(int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName), (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspace, escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName),
m->specialWorkspaceID, escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, m->specialWorkspaceID, escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"), (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false")); (m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"),
m->tearingState.activelyTearing ? "true" : "false");
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -85,13 +87,13 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial " std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
"workspace: {} ({})\n\treserved: {} " "workspace: {} ({})\n\treserved: {} "
"{} {} {}\n\tscale: {:.2f}\n\ttransform: " "{} {} {}\n\tscale: {:.2f}\n\ttransform: "
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\n", "{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
(m->output->description ? m->output->description : ""), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->description ? m->output->description : ""), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
(m->output->serial ? m->output->serial : ""), m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName, m->specialWorkspaceID, (m->output->serial ? m->output->serial : ""), m->activeWorkspace, g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName, m->specialWorkspaceID,
getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x,
(int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus,
(int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED)); (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing);
} }
} }
@@ -103,33 +105,34 @@ static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat form
if (!w->m_sGroupData.pNextWindow) if (!w->m_sGroupData.pNextWindow)
return isJson ? "" : "0"; return isJson ? "" : "0";
std::vector<CWindow*> groupMembers;
CWindow* curr = w;
do {
groupMembers.push_back(curr);
curr = curr->m_sGroupData.pNextWindow;
} while (curr != w);
const auto comma = isJson ? ", " : ",";
std::ostringstream result; std::ostringstream result;
bool first = true; CWindow* head = w->getGroupHead();
for (auto& gw : groupMembers) { CWindow* curr = head;
if (first) while (true) {
first = false;
else
result << comma;
if (isJson) if (isJson)
result << std::format("\"0x{:x}\"", (uintptr_t)gw); result << std::format("\"0x{:x}\"", (uintptr_t)curr);
else else
result << std::format("{:x}", (uintptr_t)gw); result << std::format("{:x}", (uintptr_t)curr);
curr = curr->m_sGroupData.pNextWindow;
// We've wrapped around to the start, break out without trailing comma
if (curr == head)
break;
result << (isJson ? ", " : ",");
} }
return result.str(); return result.str();
} }
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) { static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
auto getFocusHistoryID = [](CWindow* wnd) -> int {
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) {
if (g_pCompositor->m_vWindowFocusHistory[i] == wnd)
return i;
}
return -1;
};
if (format == HyprCtl::FORMAT_JSON) { if (format == HyprCtl::FORMAT_JSON) {
return std::format( return std::format(
R"#({{ R"#({{
@@ -155,7 +158,8 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
"fullscreenMode": {}, "fullscreenMode": {},
"fakeFullscreen": {}, "fakeFullscreen": {},
"grouped": [{}], "grouped": [{}],
"swallowing": "0x{:x}" "swallowing": "0x{:x}",
"focusHistoryID": {}
}},)#", }},)#",
(uintptr_t)w, (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y, (uintptr_t)w, (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID, (int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID,
@@ -166,13 +170,13 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
escapeJSONStrings(g_pXWaylandManager->getTitle(w)), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), escapeJSONStrings(g_pXWaylandManager->getTitle(w)), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(),
((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? (int)g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0), (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? (int)g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), (uintptr_t)w->m_pSwallowed); w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), (uintptr_t)w->m_pSwallowed, getFocusHistoryID(w));
} else { } else {
return std::format( return std::format(
"Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: " "Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\txwayland: {}\n\tpinned: " "{}\n\txwayland: {}\n\tpinned: "
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\n", "{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
(uintptr_t)w, w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y, (uintptr_t)w, w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID, (int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID,
(w->m_iWorkspaceID == -1 ? "" : (w->m_iWorkspaceID == -1 ? "" :
@@ -181,7 +185,7 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
(int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w), g_pXWaylandManager->getTitle(w), w->m_szInitialClass, w->m_szInitialTitle, (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w), g_pXWaylandManager->getTitle(w), w->m_szInitialClass, w->m_szInitialTitle,
w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0), (w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
(int)w->m_bFakeFullscreenState, getGroupedData(w, format), (uintptr_t)w->m_pSwallowed); (int)w->m_bFakeFullscreenState, getGroupedData(w, format), (uintptr_t)w->m_pSwallowed, getFocusHistoryID(w));
} }
} }
@@ -213,23 +217,70 @@ static std::string getWorkspaceData(CWorkspace* w, HyprCtl::eHyprCtlOutputFormat
"id": {}, "id": {},
"name": "{}", "name": "{}",
"monitor": "{}", "monitor": "{}",
"monitorID": {},
"windows": {}, "windows": {},
"hasfullscreen": {}, "hasfullscreen": {},
"lastwindow": "0x{:x}", "lastwindow": "0x{:x}",
"lastwindowtitle": "{}" "lastwindowtitle": "{}"
}})#", }})#",
w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"), g_pCompositor->getWindowsOnWorkspace(w->m_iID), w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"),
escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), g_pCompositor->getWindowsOnWorkspace(w->m_iID),
((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), (uintptr_t)PLASTW, PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : ""); ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), (uintptr_t)PLASTW, PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
} else { } else {
return std::format("workspace ID {} ({}) on monitor {}:\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID, w->m_szName, return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID,
PMONITOR ? PMONITOR->szName : "?", g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow, (uintptr_t)PLASTW, w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", g_pCompositor->getWindowsOnWorkspace(w->m_iID),
PLASTW ? PLASTW->m_szTitle : ""); (int)w->m_bHasFullscreenWindow, (uintptr_t)PLASTW, PLASTW ? PLASTW->m_szTitle : "");
} }
} }
static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprCtlOutputFormat format) {
const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; };
if (format == HyprCtl::FORMAT_JSON) {
const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor));
const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : "";
const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : "";
const std::string gapsIn = (bool)(r.gapsIn) ? std::format(",\n \"gapsIn\": {}", r.gapsIn.value()) : "";
const std::string gapsOut = (bool)(r.gapsOut) ? std::format(",\n \"gapsOut\": {}", r.gapsOut.value()) : "";
const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : "";
const std::string border = (bool)(r.border) ? std::format(",\n \"border\": {}", boolToString(r.border.value())) : "";
const std::string rounding = (bool)(r.rounding) ? std::format(",\n \"rounding\": {}", boolToString(r.rounding.value())) : "";
const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : "";
const std::string shadow = (bool)(r.shadow) ? std::format(",\n \"shadow\": {}", boolToString(r.shadow.value())) : "";
std::string result = std::format(R"#({{
"workspaceString": "{}"{}{}{}{}{}{}{}{}
}})#",
escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow);
return result;
} else {
const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "<unset>" : escapeJSONStrings(r.monitor));
const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : "<unset>");
const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : "<unset>");
const std::string gapsIn = std::format("\tgapsIn: {}\n", (bool)(r.gapsIn) ? std::to_string(r.gapsIn.value()) : "<unset>");
const std::string gapsOut = std::format("\tgapsOut: {}\n", (bool)(r.gapsOut) ? std::to_string(r.gapsOut.value()) : "<unset>");
const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>");
const std::string border = std::format("\tborder: {}\n", (bool)(r.border) ? boolToString(r.border.value()) : "<unset>");
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.rounding) ? boolToString(r.rounding.value()) : "<unset>");
const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>");
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.shadow) ? boolToString(r.shadow.value()) : "<unset>");
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow);
return result;
}
}
std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
if (!g_pCompositor->m_pLastMonitor)
return "unsafe state";
std::string result = ""; std::string result = "";
auto w = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); auto w = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
if (!w)
return "internal error";
return getWorkspaceData(w, format); return getWorkspaceData(w, format);
} }
@@ -254,6 +305,26 @@ std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
return result; return result;
} }
std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) {
std::string result = "";
if (format == HyprCtl::FORMAT_JSON) {
result += "[";
for (auto& r : g_pConfigManager->getAllWorkspaceRules()) {
result += getWorkspaceRuleData(r, format);
result += ",";
}
trimTrailingComma(result);
result += "]";
} else {
for (auto& r : g_pConfigManager->getAllWorkspaceRules()) {
result += getWorkspaceRuleData(r, format);
}
}
return result;
}
std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) { std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
@@ -835,6 +906,7 @@ std::string dispatchSetCursor(std::string request) {
std::string theme = ""; std::string theme = "";
for (size_t i = 1; i < vars.size() - 1; ++i) for (size_t i = 1; i < vars.size() - 1; ++i)
theme += vars[i] + " "; theme += vars[i] + " ";
if (!theme.empty())
theme.pop_back(); theme.pop_back();
int size = 0; int size = 0;
@@ -951,7 +1023,7 @@ std::string dispatchSetProp(std::string request) {
bool lock = false; bool lock = false;
if (vars.size() > 4) { if (vars.size() > 4) {
if (vars[4].find("lock") == 0) { if (vars[4].starts_with("lock")) {
lock = true; lock = true;
} }
} }
@@ -1001,6 +1073,10 @@ std::string dispatchSetProp(std::string request) {
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "keepaspectratio") { } else if (PROP == "keepaspectratio") {
PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "immediate") {
PWINDOW->m_sAdditionalConfigData.forceTearing.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nearestneighbor") {
PWINDOW->m_sAdditionalConfigData.nearestNeighbor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else { } else {
return "prop not found"; return "prop not found";
} }
@@ -1247,6 +1323,8 @@ std::string getReply(std::string request) {
return monitorsRequest(format); return monitorsRequest(format);
else if (request == "workspaces") else if (request == "workspaces")
return workspacesRequest(format); return workspacesRequest(format);
else if (request == "workspacerules")
return workspaceRulesRequest(format);
else if (request == "activeworkspace") else if (request == "activeworkspace")
return activeWorkspaceRequest(format); return activeWorkspaceRequest(format);
else if (request == "clients") else if (request == "clients")
@@ -1259,7 +1337,7 @@ std::string getReply(std::string request) {
return layersRequest(format); return layersRequest(format);
else if (request == "version") else if (request == "version")
return versionRequest(format); return versionRequest(format);
else if (request.find("reload") == 0) else if (request.starts_with("reload"))
return reloadRequest(request); return reloadRequest(request);
else if (request == "devices") else if (request == "devices")
return devicesRequest(format); return devicesRequest(format);
@@ -1273,27 +1351,27 @@ std::string getReply(std::string request) {
return globalShortcutsRequest(format); return globalShortcutsRequest(format);
else if (request == "animations") else if (request == "animations")
return animationsRequest(format); return animationsRequest(format);
else if (request.find("plugin") == 0) else if (request.starts_with("plugin"))
return dispatchPlugin(request); return dispatchPlugin(request);
else if (request.find("notify") == 0) else if (request.starts_with("notify"))
return dispatchNotify(request); return dispatchNotify(request);
else if (request.find("setprop") == 0) else if (request.starts_with("setprop"))
return dispatchSetProp(request); return dispatchSetProp(request);
else if (request.find("seterror") == 0) else if (request.starts_with("seterror"))
return dispatchSeterror(request); return dispatchSeterror(request);
else if (request.find("switchxkblayout") == 0) else if (request.starts_with("switchxkblayout"))
return switchXKBLayoutRequest(request); return switchXKBLayoutRequest(request);
else if (request.find("output") == 0) else if (request.starts_with("output"))
return dispatchOutput(request); return dispatchOutput(request);
else if (request.find("dispatch") == 0) else if (request.starts_with("dispatch"))
return dispatchRequest(request); return dispatchRequest(request);
else if (request.find("keyword") == 0) else if (request.starts_with("keyword"))
return dispatchKeyword(request); return dispatchKeyword(request);
else if (request.find("setcursor") == 0) else if (request.starts_with("setcursor"))
return dispatchSetCursor(request); return dispatchSetCursor(request);
else if (request.find("getoption") == 0) else if (request.starts_with("getoption"))
return dispatchGetOption(request, format); return dispatchGetOption(request, format);
else if (request.find("[[BATCH]]") == 0) else if (request.starts_with("[[BATCH]]"))
return dispatchBatch(request); return dispatchBatch(request);
return "unknown request"; return "unknown request";

View File

@@ -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); 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); g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
} }

View File

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

View File

@@ -3,7 +3,7 @@
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
CHyprNotificationOverlay::CHyprNotificationOverlay() { 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) if (m_dNotifications.size() == 0)
return; return;
@@ -44,9 +44,13 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC
PNOTIF->started.reset(); PNOTIF->started.reset();
PNOTIF->timeMs = timeMs; PNOTIF->timeMs = timeMs;
PNOTIF->icon = icon; 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_DURATION_MS = 600.0;
static constexpr auto ANIM_LAG_MS = 100.0; static constexpr auto ANIM_LAG_MS = 100.0;
static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0; static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0;
@@ -166,7 +170,7 @@ wlr_box CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
// cleanup notifs // cleanup notifs
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; }); 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) { void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
@@ -197,7 +201,7 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
cairo_surface_flush(m_pCairoSurface); cairo_surface_flush(m_pCairoSurface);
wlr_box damage = drawNotifications(pMonitor); CBox damage = drawNotifications(pMonitor);
g_pHyprRenderer->damageBox(&damage); g_pHyprRenderer->damageBox(&damage);
g_pHyprRenderer->damageBox(&m_bLastDamage); 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); 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); 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); void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
private: private:
wlr_box drawNotifications(CMonitor* pMonitor); CBox drawNotifications(CMonitor* pMonitor);
wlr_box m_bLastDamage; CBox m_bLastDamage;
std::deque<std::unique_ptr<SNotification>> m_dNotifications; std::deque<std::unique_ptr<SNotification>> m_dNotifications;

View File

@@ -10,6 +10,12 @@ void Debug::init(const std::string& IS) {
} }
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) { void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
if (disableLogs && *disableLogs)
return;
if (level > wlr_log_get_verbosity())
return;
char* outputStr = nullptr; char* outputStr = nullptr;
std::ofstream ofs; std::ofstream ofs;

View File

@@ -1,10 +1,10 @@
#pragma once #pragma once
#include <string> #include <string>
#include <wlr/util/log.h>
#include <format> #include <format>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <chrono> #include <chrono>
#include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#define LOGMESSAGESIZE 1024 #define LOGMESSAGESIZE 1024

View File

@@ -62,6 +62,7 @@ namespace Events {
DYNLISTENFUNC(setOverrideRedirect); DYNLISTENFUNC(setOverrideRedirect);
DYNLISTENFUNC(associateX11); DYNLISTENFUNC(associateX11);
DYNLISTENFUNC(dissociateX11); DYNLISTENFUNC(dissociateX11);
DYNLISTENFUNC(ackConfigure);
// Window subsurfaces // Window subsurfaces
// LISTENER(newSubsurfaceWindow); // LISTENER(newSubsurfaceWindow);
@@ -174,4 +175,7 @@ namespace Events {
// Cursor shape // Cursor shape
LISTENER(setCursorShape); LISTENER(setCursorShape);
// Tearing hints
LISTENER(newTearingHint);
}; };

View File

@@ -95,7 +95,7 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
PMONITOR->scheduledRecalc = true; PMONITOR->scheduledRecalc = true;
// and damage // and damage
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height}; layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
} }
@@ -142,7 +142,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output); 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 // don't focus if constrained
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint); (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
@@ -157,7 +157,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y); 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, CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height}; layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
@@ -171,7 +171,8 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")}); g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
EMIT_HOOK_EVENT("openLayer", layersurface); 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) { void Events::listener_unmapLayerSurface(void* owner, void* data) {
@@ -246,7 +247,7 @@ 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, CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height}; layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
@@ -269,7 +270,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) 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 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); g_pHyprRenderer->damageBox(&geomFixed);
// fix if it changed its mon // fix if it changed its mon
@@ -342,5 +343,6 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y); 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

@@ -237,3 +237,43 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
g_pInputManager->processMouseRequest(E); 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

@@ -28,8 +28,9 @@ void Events::listener_change(wl_listener* listener, void* data) {
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output); const auto CONFIGHEAD = wlr_output_configuration_head_v1_create(CONFIG, m->output);
wlr_box BOX; CBox BOX;
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, &BOX); wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, BOX.pWlr());
BOX.applyFromWlr();
//m->vecSize.x = BOX.width; //m->vecSize.x = BOX.width;
// m->vecSize.y = BOX.height; // m->vecSize.y = BOX.height;
@@ -67,45 +68,31 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
return; return;
} }
if (g_pCompositor->m_bUnsafeState)
Debug::log(WARN, "Recovering from an unsafe state. May you be lucky.");
// add it to real // add it to real
std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr; std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>()); PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared<CMonitor>());
if (std::string("HEADLESS-1") == OUTPUT->name)
g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get();
(*PNEWMONITORWRAP)->ID = g_pCompositor->getNextAvailableMonitorID(OUTPUT->name); (*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(); const auto PNEWMONITOR = PNEWMONITORWRAP->get();
PNEWMONITOR->isUnsafeFallback = FALLBACK;
PNEWMONITOR->output = OUTPUT; if (!FALLBACK)
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
PNEWMONITOR->onConnect(false); PNEWMONITOR->onConnect(false);
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
return;
// ready to process if we have a real monitor
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled) if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR; g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
// ready to process cuz we have a monitor
if (PNEWMONITOR->m_bEnabled) {
if (g_pCompositor->m_bUnsafeState) {
// recover workspaces
for (auto& ws : g_pCompositor->m_vWorkspaces) {
g_pCompositor->moveWorkspaceToMonitor(ws.get(), PNEWMONITOR);
}
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
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);
}
g_pCompositor->m_bReadyToProcess = true; g_pCompositor->m_bReadyToProcess = true;
g_pCompositor->m_bUnsafeState = false;
}
g_pConfigManager->m_bWantsMonitorReload = true; g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR); g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
@@ -131,8 +118,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) { if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!"); Debug::log(WARN, "Attempted to render frame on inactive session!");
if (g_pCompositor->m_bUnsafeState) if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
g_pConfigManager->performMonitorReload(); return m->output != g_pCompositor->m_pUnsafeOutput->output;
})) {
// restore from unsafe state
g_pCompositor->leaveUnsafeState();
}
return; // cannot draw on session inactive (different tty) return; // cannot draw on session inactive (different tty)
} }
@@ -140,12 +131,25 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (!PMONITOR->m_bEnabled) if (!PMONITOR->m_bEnabled)
return; 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 PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue; static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
PMONITOR->lastPresentationTimer.reset(); PMONITOR->lastPresentationTimer.reset();
if (*PENABLERAT) { if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
if (!PMONITOR->RATScheduled) { if (!PMONITOR->RATScheduled) {
// render // render
g_pHyprRenderer->renderMonitor(PMONITOR); g_pHyprRenderer->renderMonitor(PMONITOR);
@@ -226,7 +230,7 @@ void Events::listener_monitorCommit(void* owner, void* data) {
const auto E = (wlr_output_event_commit*)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_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E); g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
} }

View File

@@ -64,9 +64,9 @@ void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
const auto PMONITOR = g_pCompositor->m_pLastMonitor; const auto PMONITOR = g_pCompositor->m_pLastMonitor;
wlr_box box = {.x = PMONITOR->vecPosition.x - pHyprPopup->lx, .y = PMONITOR->vecPosition.y - pHyprPopup->ly, .width = PMONITOR->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; pHyprPopup->monitor = PMONITOR;
@@ -159,13 +159,16 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0; int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly); addPopupGlobalCoords(PPOPUP, &lx, &ly);
wlr_box extents; CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &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); g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
if (PPOPUP->monitor) if (PPOPUP->monitor) {
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale); 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 {:x}", (uintptr_t)PPOPUP->pSurfaceTree); Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree);
} }
@@ -178,11 +181,18 @@ void Events::listener_repositionPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0; int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly); addPopupGlobalCoords(PPOPUP, &lx, &ly);
wlr_box extents; CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents); wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
PPOPUP->lastPos = {lx - extents.x, ly - extents.y}; PPOPUP->lastPos = {lx - extents.x, ly - extents.y};
PPOPUP->repositionRequested = true; 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) { void Events::listener_unmapPopupXDG(void* owner, void* data) {
@@ -199,8 +209,9 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0; int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly); addPopupGlobalCoords(PPOPUP, &lx, &ly);
wlr_box extents; CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &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); g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
@@ -225,8 +236,9 @@ void Events::listener_commitPopupXDG(void* owner, void* data) {
int lx = 0, ly = 0; int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly); addPopupGlobalCoords(PPOPUP, &lx, &ly);
wlr_box extents; CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, &extents); wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
if (PPOPUP->repositionRequested) if (PPOPUP->repositionRequested)
g_pHyprRenderer->damageBox(PPOPUP->lastPos.x, PPOPUP->lastPos.y, extents.width + 2, extents.height + 2); g_pHyprRenderer->damageBox(PPOPUP->lastPos.x, PPOPUP->lastPos.y, extents.width + 2, extents.height + 2);

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 PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue; static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_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; auto PMONITOR = g_pCompositor->m_pLastMonitor;
const auto PWORKSPACE = const auto PWORKSPACE =
@@ -95,7 +96,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PWORKSPACE->m_bDefaultPseudo) { if (PWORKSPACE->m_bDefaultPseudo) {
PWINDOW->m_bIsPseudotiled = true; PWINDOW->m_bIsPseudotiled = true;
wlr_box desiredGeometry = {0}; CBox desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry); g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry);
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height); PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
} }
@@ -116,7 +117,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW); PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW);
for (auto& r : WINDOWRULES) { for (auto& r : WINDOWRULES) {
if (r.szRule.find("monitor") == 0) { if (r.szRule.starts_with("monitor")) {
try { try {
const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' '))); const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' ')));
@@ -150,7 +151,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW); 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()); } } catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
} else if (r.szRule.find("workspace") == 0) { } else if (r.szRule.starts_with("workspace")) {
// check if it isnt unset // check if it isnt unset
const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1); const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
@@ -166,19 +167,19 @@ void Events::listener_mapWindow(void* owner, void* data) {
requestedWorkspace = ""; requestedWorkspace = "";
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r.szValue); Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r.szValue);
} else if (r.szRule.find("float") == 0) { } else if (r.szRule.starts_with("float")) {
PWINDOW->m_bIsFloating = true; PWINDOW->m_bIsFloating = true;
} else if (r.szRule.find("tile") == 0) { } else if (r.szRule.starts_with("tile")) {
PWINDOW->m_bIsFloating = false; PWINDOW->m_bIsFloating = false;
} else if (r.szRule.find("pseudo") == 0) { } else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true; PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.find("nofocus") == 0) { } else if (r.szRule.starts_with("nofocus")) {
PWINDOW->m_bNoFocus = true; PWINDOW->m_bNoFocus = true;
} else if (r.szRule.find("noinitialfocus") == 0) { } else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.find("nofullscreenrequest") == 0) { } else if (r.szRule.starts_with("nofullscreenrequest")) {
PWINDOW->m_bNoFullscreenRequest = true; PWINDOW->m_bNoFullscreenRequest = true;
} else if (r.szRule.find("nomaximizerequest") == 0) { } else if (r.szRule.starts_with("nomaximizerequest")) {
PWINDOW->m_bNoMaximizeRequest = true; PWINDOW->m_bNoMaximizeRequest = true;
} else if (r.szRule == "fullscreen") { } else if (r.szRule == "fullscreen") {
requestsFullscreen = true; requestsFullscreen = true;
@@ -198,7 +199,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
overridingNoMaximize = true; overridingNoMaximize = true;
} else if (r.szRule == "stayfocused") { } else if (r.szRule == "stayfocused") {
PWINDOW->m_bStayFocused = true; PWINDOW->m_bStayFocused = true;
} else if (r.szRule.find("group") == 0) { } else if (r.szRule.starts_with("group")) {
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE) if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
continue; continue;
@@ -245,7 +246,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
vPrev = v; vPrev = v;
} }
} else if (r.szRule.find("idleinhibit") == 0) { } else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (IDLERULE == "none") { if (IDLERULE == "none") {
@@ -263,13 +264,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->applyDynamicRule(r); 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(); PWINDOW->updateSpecialRenderData();
// disallow tiled pinned // disallow tiled pinned
@@ -279,7 +273,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
const CVarList WORKSPACEARGS = CVarList(requestedWorkspace, 0, ' '); const CVarList WORKSPACEARGS = CVarList(requestedWorkspace, 0, ' ');
if (!WORKSPACEARGS[0].empty()) { if (!WORKSPACEARGS[0].empty()) {
if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].find("silent") == 0) if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].starts_with("silent"))
workspaceSilent = true; workspaceSilent = true;
std::string requestedWorkspaceName; std::string requestedWorkspaceName;
@@ -315,7 +309,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// size and move rules // size and move rules
for (auto& r : WINDOWRULES) { for (auto& r : WINDOWRULES) {
if (r.szRule.find("size") == 0) { if (r.szRule.starts_with("size")) {
try { try {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
@@ -337,7 +331,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->setHidden(false); PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); } } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.find("minsize") == 0) { } else if (r.szRule.starts_with("minsize")) {
try { try {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
@@ -351,7 +345,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->setHidden(false); PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule minsize failed, rule: {} -> {}", r.szRule, r.szValue); } } catch (...) { Debug::log(LOG, "Rule minsize failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.find("maxsize") == 0) { } else if (r.szRule.starts_with("maxsize")) {
try { try {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
@@ -365,16 +359,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->setHidden(false); PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule maxsize failed, rule: {} -> {}", r.szRule, r.szValue); } } catch (...) { Debug::log(LOG, "Rule maxsize failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.find("move") == 0) { } else if (r.szRule.starts_with("move")) {
try { try {
auto value = r.szRule.substr(r.szRule.find(' ') + 1); auto value = r.szRule.substr(r.szRule.find(' ') + 1);
const bool ONSCREEN = value.find("onscreen") == 0; const bool ONSCREEN = value.starts_with("onscreen");
if (ONSCREEN) if (ONSCREEN)
value = value.substr(value.find_first_of(' ') + 1); value = value.substr(value.find_first_of(' ') + 1);
const bool CURSOR = value.find("cursor") == 0; const bool CURSOR = value.starts_with("cursor");
if (CURSOR) if (CURSOR)
value = value.substr(value.find_first_of(' ') + 1); value = value.substr(value.find_first_of(' ') + 1);
@@ -385,7 +379,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
int posX = 0; int posX = 0;
int posY = 0; int posY = 0;
if (POSXSTR.find("100%-") == 0) { if (POSXSTR.starts_with("100%-")) {
const auto POSXRAW = POSXSTR.substr(5); const auto POSXRAW = POSXSTR.substr(5);
posX = posX =
PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x); PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
@@ -404,7 +398,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
} }
if (POSYSTR.find("100%-") == 0) { if (POSYSTR.starts_with("100%-")) {
const auto POSYRAW = POSYSTR.substr(5); const auto POSYRAW = POSYSTR.substr(5);
posY = posY =
PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y); PMONITOR->vecSize.y - (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y);
@@ -439,7 +433,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->setHidden(false); PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r.szRule, r.szValue); } } catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.find("center") == 0) { } else if (r.szRule.starts_with("center")) {
auto RESERVEDOFFSET = Vector2D(); auto RESERVEDOFFSET = Vector2D();
const auto ARGS = CVarList(r.szRule, 2, ' '); const auto ARGS = CVarList(r.szRule, 2, ' ');
if (ARGS[1] == "1") if (ARGS[1] == "1")
@@ -474,6 +468,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive) if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
PWINDOW->m_bNoInitialFocus = true; 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 && 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 && (PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
@@ -500,6 +504,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_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, PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW,
"XDG Window Late"); "XDG Window Late");
PWINDOW->hyprListener_ackConfigure.initCallback(&PWINDOW->m_uSurface.xdg->events.ack_configure, &Events::listener_ackConfigure, PWINDOW, "XDG Window Late");
} else { } else {
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW, PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW,
"XWayland Window Late"); "XWayland Window Late");
@@ -543,10 +548,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
} }
if (pFullscreenWindow && workspaceSilent) {
g_pCompositor->setWindowFullscreen(pFullscreenWindow, true, PWORKSPACE->m_efFullscreenMode);
}
// recheck idle inhibitors // recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
@@ -642,8 +643,18 @@ void Events::listener_mapWindow(void* owner, void* data) {
// recalc the values for this window // recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); 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) { void Events::listener_unmapWindow(void* owner, void* data) {
@@ -657,6 +668,13 @@ void Events::listener_unmapWindow(void* owner, void* data) {
return; return;
} }
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)}); g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
EMIT_HOOK_EVENT("closeWindow", PWINDOW); EMIT_HOOK_EVENT("closeWindow", PWINDOW);
@@ -672,6 +690,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->hyprListener_requestMove.removeCallback(); PWINDOW->hyprListener_requestMove.removeCallback();
PWINDOW->hyprListener_requestResize.removeCallback(); PWINDOW->hyprListener_requestResize.removeCallback();
PWINDOW->hyprListener_fullscreenWindow.removeCallback(); PWINDOW->hyprListener_fullscreenWindow.removeCallback();
PWINDOW->hyprListener_ackConfigure.removeCallback();
} else { } else {
Debug::log(LOG, "Unregistered late callbacks XWL"); Debug::log(LOG, "Unregistered late callbacks XWL");
PWINDOW->hyprListener_fullscreenWindow.removeCallback(); PWINDOW->hyprListener_fullscreenWindow.removeCallback();
@@ -685,13 +704,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (PWINDOW->m_bIsFullscreen) if (PWINDOW->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); 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. // Allow the renderer to catch the last frame.
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW); g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
@@ -731,13 +743,17 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE); Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE);
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow) { if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
if (!PWINDOWCANDIDATE)
g_pInputManager->simulateMouseMovement();
else
g_pCompositor->focusWindow(PWINDOWCANDIDATE); g_pCompositor->focusWindow(PWINDOWCANDIDATE);
} else {
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == PWINDOWCANDIDATE)
g_pInputManager->simulateMouseMovement(); 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 { } else {
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus."); Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
@@ -774,12 +790,33 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->onUnmap(); 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) { void Events::listener_commitWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11)) if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11))
return; 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(); PWINDOW->updateSurfaceOutputs();
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
@@ -839,8 +876,8 @@ void Events::listener_destroyWindow(void* owner, void* data) {
PWINDOW->m_bReadyToDelete = true; PWINDOW->m_bReadyToDelete = true;
if (!PWINDOW->m_bFadingOut) { if (!PWINDOW->m_bFadingOut) {
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW); Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
} }
} }
@@ -997,6 +1034,7 @@ void Events::listener_configureX11(void* owner, void* data) {
if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bMappedX11) { 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); wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
PWINDOW->m_vReportedSize = {E->width, E->height};
return; return;
} }
@@ -1021,8 +1059,11 @@ void Events::listener_configureX11(void* owner, void* data) {
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue; static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
if (*PXWLFORCESCALEZERO) { 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_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(); PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
@@ -1042,6 +1083,8 @@ void Events::listener_configureX11(void* owner, void* data) {
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
PWINDOW->m_vReportedSize = {E->width, E->height};
} }
void Events::listener_unmanagedSetGeometry(void* owner, void* data) { void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
@@ -1080,8 +1123,11 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height)); PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height));
if (*PXWLFORCESCALEZERO) { 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_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(); PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();

View File

@@ -6,6 +6,7 @@
#include "Vector2D.hpp" #include "Vector2D.hpp"
#include "Color.hpp" #include "Color.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../debug/Log.hpp"
enum ANIMATEDVARTYPE enum ANIMATEDVARTYPE
{ {

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

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

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

@@ -0,0 +1,83 @@
#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);
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 { class CColor {
public: public:
CColor(); CColor();
CColor(float, float, float, float); CColor(float r, float g, float b, float a);
CColor(uint64_t); CColor(uint64_t);
float r = 0, g = 0, b = 0, a = 1.f; float r = 0, g = 0, b = 0, a = 1.f;
@@ -27,4 +27,8 @@ class CColor {
bool operator==(const CColor& c2) const { bool operator==(const CColor& c2) const {
return r == c2.r && g == c2.g && b == c2.b && a == c2.a; return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
} }
CColor stripA() const {
return {r, g, b, 1};
}
}; };

View File

@@ -2,11 +2,14 @@
#include "../defines.hpp" #include "../defines.hpp"
#include <algorithm> #include <algorithm>
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include <optional>
#include <set> #include <set>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#ifdef HAS_EXECINFO
#include <execinfo.h> #include <execinfo.h>
#endif
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sysctl.h> #include <sys/sysctl.h>
@@ -182,13 +185,6 @@ std::string escapeJSONStrings(const std::string& str) {
return oss.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) { std::string removeBeginEndSpacesTabs(std::string str) {
if (str.empty()) if (str.empty())
return str; return str;
@@ -246,9 +242,13 @@ bool isDirection(const std::string& arg) {
return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b"; 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 getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int result = INT_MAX; int result = INT_MAX;
if (in.find("special") == 0) { if (in.starts_with("special")) {
outName = "special"; outName = "special";
if (in.length() > 8) { if (in.length() > 8) {
@@ -262,7 +262,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
} }
return SPECIAL_WORKSPACE_START; 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 WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME); const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
if (!WORKSPACE) { if (!WORKSPACE) {
@@ -271,14 +271,14 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
result = WORKSPACE->m_iID; result = WORKSPACE->m_iID;
} }
outName = WORKSPACENAME; outName = WORKSPACENAME;
} else if (in.find("empty") == 0) { } else if (in.starts_with("empty")) {
int id = 0; int id = 0;
while (++id < INT_MAX) { while (++id < INT_MAX) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0)) if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0))
return id; return id;
} }
} else if (in.find("prev") == 0) { } else if (in.starts_with("prev")) {
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_pLastMonitor)
return INT_MAX; return INT_MAX;
@@ -389,12 +389,12 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int beginID = finalWSID; int beginID = finalWSID;
int curID = finalWSID; int curID = finalWSID;
while (--curID > 0 && remainingWSes > 0) { while (--curID > 0 && remainingWSes > 0) {
if (invalidWSes.find(curID) == invalidWSes.end()) { if (!invalidWSes.contains(curID)) {
remainingWSes--; remainingWSes--;
} }
finalWSID = curID; finalWSID = curID;
} }
if (finalWSID <= 0 || invalidWSes.find(finalWSID) != invalidWSes.end()) { if (finalWSID <= 0 || invalidWSes.contains(finalWSID)) {
if (namedWSes.size()) { if (namedWSes.size()) {
// Go to the named workspaces // Go to the named workspaces
// Need remainingWSes more // Need remainingWSes more
@@ -414,7 +414,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
if (walkDir == '+') { if (walkDir == '+') {
int curID = finalWSID; int curID = finalWSID;
while (++curID < INT32_MAX && remainingWSes > 0) { while (++curID < INT32_MAX && remainingWSes > 0) {
if (invalidWSes.find(curID) == invalidWSes.end()) { if (!invalidWSes.contains(curID)) {
remainingWSes--; remainingWSes--;
} }
finalWSID = curID; finalWSID = curID;
@@ -501,6 +501,43 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
return result; 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) { 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 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}); const float DY = std::max({0.0, p1.y - vec.y, vec.y - p2.y});
@@ -626,11 +663,11 @@ int64_t getPPIDof(int64_t pid) {
} }
int64_t configStringToInt(const std::string& VALUE) { int64_t configStringToInt(const std::string& VALUE) {
if (VALUE.find("0x") == 0) { if (VALUE.starts_with("0x")) {
// Values with 0x are hex // Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2); const auto VALUEWITHOUTHEX = VALUE.substr(2);
return stol(VALUEWITHOUTHEX, nullptr, 16); 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); const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) { if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
@@ -642,7 +679,7 @@ int64_t configStringToInt(const std::string& VALUE) {
// now we need to RGBA -> ARGB. The config holds ARGB only. // now we need to RGBA -> ARGB. The config holds ARGB only.
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF); 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); const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) { if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
@@ -653,9 +690,9 @@ int64_t configStringToInt(const std::string& VALUE) {
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16); const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
return RGB + 0xFF000000; // 0xFF for opaque 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; 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; return 0;
} }
return std::stoll(VALUE); return std::stoll(VALUE);
@@ -689,6 +726,7 @@ std::string replaceInString(std::string subject, const std::string& search, cons
std::vector<SCallstackFrameInfo> getBacktrace() { std::vector<SCallstackFrameInfo> getBacktrace() {
std::vector<SCallstackFrameInfo> callstack; std::vector<SCallstackFrameInfo> callstack;
#ifdef HAS_EXECINFO
void* bt[1024]; void* bt[1024];
size_t btSize; size_t btSize;
char** btSymbols; char** btSymbols;
@@ -699,6 +737,9 @@ std::vector<SCallstackFrameInfo> getBacktrace() {
for (size_t i = 0; i < btSize; ++i) { for (size_t i = 0; i < btSize; ++i) {
callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[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; return callstack;
} }
@@ -707,3 +748,20 @@ void throwError(const std::string& err) {
Debug::log(CRIT, "Critical error thrown: {}", err); Debug::log(CRIT, "Critical error thrown: {}", err);
throw std::runtime_error(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;
}

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <optional>
#include <string> #include <string>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/util/box.h> #include <wlr/util/box.h>
@@ -15,11 +16,12 @@ struct SCallstackFrameInfo {
std::string absolutePath(const std::string&, const std::string&); std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString); void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
std::string escapeJSONStrings(const std::string& str); std::string escapeJSONStrings(const std::string& str);
void scaleBox(wlr_box*, float);
std::string removeBeginEndSpacesTabs(std::string); std::string removeBeginEndSpacesTabs(std::string);
bool isNumber(const std::string&, bool allowfloat = false); bool isNumber(const std::string&, bool allowfloat = false);
bool isDirection(const std::string&); bool isDirection(const std::string&);
bool isDirection(const char&);
int getWorkspaceIDFromString(const std::string&, std::string&); 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); float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
void logSystemInfo(); void logSystemInfo();
std::string execAndGet(const char*); std::string execAndGet(const char*);
@@ -31,6 +33,7 @@ double normalizeAngleRad(double ang);
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace); std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
std::vector<SCallstackFrameInfo> getBacktrace(); std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err); void throwError(const std::string& err);
uint32_t drmFormatToGL(uint32_t drm);
template <typename... Args> template <typename... Args>
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) { [[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {

View File

@@ -40,6 +40,8 @@ void CMonitor::onConnect(bool noRule) {
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this); hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, 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) { if (m_bEnabled) {
wlr_output_enable(output, 1); wlr_output_enable(output, 1);
wlr_output_commit(output); wlr_output_commit(output);
@@ -107,20 +109,20 @@ void CMonitor::onConnect(bool noRule) {
m_bRenderingInitPassed = true; m_bRenderingInitPassed = true;
} }
if (!m_pThisWrap) { std::shared_ptr<CMonitor>* thisWrapper = nullptr;
// find the wrap // find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) { if (m->ID == ID) {
m_pThisWrap = &m; thisWrapper = &m;
break; 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()) { RASSERT(thisWrapper->get(), "CMonitor::onConnect: Had no wrapper???");
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
} 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; m_bEnabled = true;
@@ -130,6 +132,8 @@ void CMonitor::onConnect(bool noRule) {
if (!noRule) if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
wlr_output_commit(output);
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y); wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale); wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
@@ -150,8 +154,6 @@ void CMonitor::onConnect(bool noRule) {
if (scale < 0.1) if (scale < 0.1)
scale = getDefaultScale(); scale = getDefaultScale();
m_pThisWrap = nullptr;
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering. forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
// //
@@ -182,6 +184,8 @@ void CMonitor::onConnect(bool noRule) {
g_pCompositor->setActiveMonitor(this); g_pCompositor->setActiveMonitor(this);
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this); renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
g_pCompositor->scheduleFrameForMonitor(this);
} }
void CMonitor::onDisconnect() { void CMonitor::onDisconnect() {
@@ -219,9 +223,6 @@ void CMonitor::onDisconnect() {
g_pConfigManager->m_bWantsMonitorReload = true; g_pConfigManager->m_bWantsMonitorReload = true;
} }
m_bEnabled = false;
m_bRenderingInitPassed = false;
hyprListener_monitorFrame.removeCallback(); hyprListener_monitorFrame.removeCallback();
hyprListener_monitorDamage.removeCallback(); hyprListener_monitorDamage.removeCallback();
hyprListener_monitorNeedsFrame.removeCallback(); hyprListener_monitorNeedsFrame.removeCallback();
@@ -243,9 +244,12 @@ void CMonitor::onDisconnect() {
if (!BACKUPMON) { if (!BACKUPMON) {
Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend."); Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend.");
g_pCompositor->m_bUnsafeState = true; g_pCompositor->enterUnsafeState();
} }
m_bEnabled = false;
m_bRenderingInitPassed = false;
if (BACKUPMON) { if (BACKUPMON) {
// snap cursor // snap cursor
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f,
@@ -254,7 +258,7 @@ void CMonitor::onDisconnect() {
// move workspaces // move workspaces
std::deque<CWorkspace*> wspToMove; std::deque<CWorkspace*> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID) { if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) {
wspToMove.push_back(w.get()); wspToMove.push_back(w.get());
} }
} }
@@ -313,14 +317,14 @@ void CMonitor::addDamage(const CRegion* rg) {
addDamage(const_cast<CRegion*>(rg)->pixman()); 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; static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
wlr_damage_ring_add_whole(&damage); wlr_damage_ring_add_whole(&damage);
g_pCompositor->scheduleFrameForMonitor(this); 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); g_pCompositor->scheduleFrameForMonitor(this);
} }
@@ -412,19 +416,22 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
vecPosition = RULE.offset; vecPosition = RULE.offset;
// push to mvmonitors // push to mvmonitors
if (!m_pThisWrap) {
std::shared_ptr<CMonitor>* thisWrapper = nullptr;
// find the wrap // find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) { if (m->ID == ID) {
m_pThisWrap = &m; thisWrapper = &m;
break; 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; }) == 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.end()) {
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap); g_pCompositor->m_vMonitors.push_back(*thisWrapper);
} }
setupDefaultWS(RULE); setupDefaultWS(RULE);
@@ -552,6 +559,8 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
g_pHyprRenderer->damageMonitor(this); g_pHyprRenderer->damageMonitor(this);
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace); g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
g_pConfigManager->ensureVRR(this);
} }
void CMonitor::changeWorkspace(const int& id, bool internal) { void CMonitor::changeWorkspace(const int& id, bool internal) {

View File

@@ -65,6 +65,8 @@ class CMonitor {
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. 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 enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false; 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 pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false; bool renderingActive = false;
@@ -81,6 +83,18 @@ class CMonitor {
CRegion lastFrameDamage; // stores last frame damage 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. // for the special workspace. 0 means not open.
int specialWorkspaceID = 0; int specialWorkspaceID = 0;
@@ -99,7 +113,7 @@ class CMonitor {
void onDisconnect(); void onDisconnect();
void addDamage(const pixman_region32_t* rg); void addDamage(const pixman_region32_t* rg);
void addDamage(const CRegion* rg); void addDamage(const CRegion* rg);
void addDamage(const wlr_box* box); void addDamage(const CBox* box);
void setMirror(const std::string&); void setMirror(const std::string&);
bool isMirror(); bool isMirror();
float getDefaultScale(); float getDefaultScale();
@@ -110,7 +124,6 @@ class CMonitor {
void moveTo(const Vector2D& pos); void moveTo(const Vector2D& pos);
Vector2D middle(); Vector2D middle();
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false; bool m_bRenderingInitPassed = false;

View File

@@ -1,6 +1,8 @@
#include "Region.hpp" #include "Region.hpp"
extern "C" {
#include <wlr/util/box.h> #include <wlr/util/box.h>
#include <wlr/util/region.h> #include <wlr/util/region.h>
}
CRegion::CRegion() { CRegion::CRegion() {
pixman_region32_init(&m_rRegion); pixman_region32_init(&m_rRegion);
@@ -19,6 +21,10 @@ CRegion::CRegion(wlr_box* box) {
pixman_region32_init_rect(&m_rRegion, box->x, box->y, box->width, box->height); 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) { CRegion::CRegion(pixman_box32_t* box) {
pixman_region32_init_rect(&m_rRegion, box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1); pixman_region32_init_rect(&m_rRegion, box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1);
} }
@@ -57,6 +63,11 @@ CRegion& CRegion::add(double x, double y, double w, double h) {
return *this; 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) { CRegion& CRegion::subtract(const CRegion& other) {
pixman_region32_subtract(&m_rRegion, &m_rRegion, const_cast<CRegion*>(&other)->pixman()); pixman_region32_subtract(&m_rRegion, &m_rRegion, const_cast<CRegion*>(&other)->pixman());
return *this; return *this;
@@ -98,7 +109,7 @@ std::vector<pixman_box32_t> CRegion::getRects() const {
return result; return result;
} }
wlr_box CRegion::getExtents() { CBox CRegion::getExtents() {
pixman_box32_t* box = pixman_region32_extents(&m_rRegion); pixman_box32_t* box = pixman_region32_extents(&m_rRegion);
return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1}; return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1};
} }

View File

@@ -2,6 +2,7 @@
#include <pixman.h> #include <pixman.h>
#include <vector> #include <vector>
#include "Vector2D.hpp" #include "Vector2D.hpp"
#include "Box.hpp"
struct wlr_box; struct wlr_box;
@@ -15,6 +16,8 @@ class CRegion {
CRegion(double x, double y, double w, double h); CRegion(double x, double y, double w, double h);
/* Create from a wlr_box */ /* Create from a wlr_box */
CRegion(wlr_box* box); CRegion(wlr_box* box);
/* Create from a CBox */
CRegion(const CBox& box);
/* Create from a pixman_box32_t */ /* Create from a pixman_box32_t */
CRegion(pixman_box32_t* box); CRegion(pixman_box32_t* box);
@@ -37,13 +40,14 @@ class CRegion {
CRegion& set(const CRegion& other); CRegion& set(const CRegion& other);
CRegion& add(const CRegion& other); CRegion& add(const CRegion& other);
CRegion& add(double x, double y, double w, double h); CRegion& add(double x, double y, double w, double h);
CRegion& add(const CBox& other);
CRegion& subtract(const CRegion& other); CRegion& subtract(const CRegion& other);
CRegion& intersect(const CRegion& other); CRegion& intersect(const CRegion& other);
CRegion& intersect(double x, double y, double w, double h); CRegion& intersect(double x, double y, double w, double h);
CRegion& translate(const Vector2D& vec); CRegion& translate(const Vector2D& vec);
CRegion& invert(pixman_box32_t* box); CRegion& invert(pixman_box32_t* box);
CRegion& scale(float scale); CRegion& scale(float scale);
wlr_box getExtents(); CBox getExtents();
bool containsPoint(const Vector2D& vec) const; bool containsPoint(const Vector2D& vec) const;
bool empty() const; bool empty() const;
Vector2D closestPoint(const Vector2D& vec) const; Vector2D closestPoint(const Vector2D& vec) const;

View File

@@ -98,8 +98,9 @@ void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
// damage // damage
if (pNode->pSurface && pNode->pSurface->exists()) { if (pNode->pSurface && pNode->pSurface->exists()) {
wlr_box extents = {}; CBox extents = {};
wlr_surface_get_extends(pNode->pSurface->wlr(), &extents); wlr_surface_get_extends(pNode->pSurface->wlr(), extents.pWlr());
extents.applyFromWlr();
int lx = 0, ly = 0; int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly); addSurfaceGlobalOffset(pNode, &lx, &ly);
@@ -198,7 +199,7 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
int lx = 0, ly = 0; int lx = 0, ly = 0;
addSurfaceGlobalOffset(PNODE, &lx, &ly); 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.width = PNODE->pSurface->wlr()->current.width;
extents.height = PNODE->pSurface->wlr()->current.height; extents.height = PNODE->pSurface->wlr()->current.height;
@@ -245,6 +246,29 @@ 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); g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE);
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);
}
}
}
}
} }
void Events::listener_destroySubsurface(void* owner, void* data) { void Events::listener_destroySubsurface(void* owner, void* data) {

View File

@@ -1,3 +1,4 @@
#include "MiscFunctions.hpp"
#include "VarList.hpp" #include "VarList.hpp"
#include <ranges> #include <ranges>
#include <algorithm> #include <algorithm>

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include <functional>
#include <vector> #include <vector>
#include <string> #include <string>
#include "../macros.hpp" #include "../macros.hpp"
@@ -20,6 +21,15 @@ class CVarList {
std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const; 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 { std::string operator[](const size_t& idx) const {
if (idx >= m_vArgs.size()) if (idx >= m_vArgs.size())
return ""; return "";

View File

@@ -28,6 +28,10 @@ Vector2D Vector2D::floor() const {
return Vector2D(std::floor(x), std::floor(y)); 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 { 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)); 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; 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

@@ -22,6 +22,9 @@ class Vector2D {
Vector2D operator-(const Vector2D& a) const { Vector2D operator-(const Vector2D& a) const {
return Vector2D(this->x - a.x, this->y - a.y); return Vector2D(this->x - a.x, this->y - a.y);
} }
Vector2D operator-() const {
return Vector2D(-this->x, -this->y);
}
Vector2D operator*(const float& a) const { Vector2D operator*(const float& a) const {
return Vector2D(this->x * a, this->y * a); return Vector2D(this->x * a, this->y * a);
} }
@@ -54,10 +57,11 @@ class Vector2D {
} }
double distance(const Vector2D& other) const; double distance(const Vector2D& other) const;
double size() const;
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const; Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const;
Vector2D floor() const; Vector2D floor() const;
Vector2D round() const;
bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const; bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const;
}; };

View File

@@ -20,7 +20,7 @@ void SLayerSurface::applyRules() {
noAnimations = true; noAnimations = true;
else if (rule.rule == "blur") else if (rule.rule == "blur")
forceBlur = true; 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(' '); const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
std::string alphaValue = ""; std::string alphaValue = "";
if (FIRST_SPACE_POS != std::string::npos) if (FIRST_SPACE_POS != std::string::npos)
@@ -31,7 +31,7 @@ void SLayerSurface::applyRules() {
if (!alphaValue.empty()) if (!alphaValue.empty())
ignoreAlphaValue = std::stof(alphaValue); ignoreAlphaValue = std::stof(alphaValue);
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); } } 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, ' '}; CVarList vars{rule.rule, 0, ' '};
try { try {
xray = configStringToInt(vars[1]); xray = configStringToInt(vars[1]);

View File

@@ -33,7 +33,7 @@ struct SLayerSurface {
DYNLISTENER(commitLayerSurface); DYNLISTENER(commitLayerSurface);
DYNLISTENER(newPopup); DYNLISTENER(newPopup);
wlr_box geometry = {0, 0, 0, 0}; CBox geometry = {0, 0, 0, 0};
Vector2D position; Vector2D position;
zwlr_layer_shell_v1_layer layer; zwlr_layer_shell_v1_layer layer;
@@ -65,12 +65,12 @@ class CMonitor;
struct SRenderData { struct SRenderData {
CMonitor* pMonitor; CMonitor* pMonitor;
timespec* when; timespec* when;
int x, y; double x, y;
// for iters // for iters
void* data = nullptr; void* data = nullptr;
wlr_surface* surface = nullptr; wlr_surface* surface = nullptr;
int w, h; double w, h;
// for rounding // for rounding
bool dontRound = true; bool dontRound = true;
@@ -169,7 +169,8 @@ struct SConstraint {
bool active = false; bool active = false;
bool hintSet = false; bool hintSet = false;
Vector2D positionHint = {-1, -1}; // the position hint, but will be set to the current cursor pos if not set. Vector2D positionHint = {-1, -1}; // the position hint, but will use cursorPosOnActivate if unset
Vector2D cursorPosOnActivate = {-1, -1};
DYNLISTENER(setConstraintRegion); DYNLISTENER(setConstraintRegion);
DYNLISTENER(destroyConstraint); DYNLISTENER(destroyConstraint);
@@ -392,3 +393,14 @@ struct SSwitchDevice {
return pWlrDevice == other.pWlrDevice; 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 "MiscFunctions.hpp"
#include <string> #include <string>
#include "../debug/Log.hpp" #include "../debug/Log.hpp"
#include "Watchdog.hpp"
void handleWrapped(wl_listener* listener, void* data) { void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener); CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
g_pWatchdog->startWatching();
try {
pWrap->m_pSelf->emit(data); 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) { CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {

View File

@@ -27,15 +27,45 @@ wlr_surface* CWLSurface::wlr() const {
return m_pWLRSurface; 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() { void CWLSurface::destroy() {
if (!m_pWLRSurface) if (!m_pWLRSurface)
return; return;
hyprListener_destroy.removeCallback(); hyprListener_destroy.removeCallback();
m_pWLRSurface->data = nullptr; m_pWLRSurface->data = nullptr;
m_pOwner = nullptr;
if (g_pCompositor->m_pLastFocus == m_pWLRSurface) if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
g_pCompositor->m_pLastFocus = nullptr; 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_pInputManager->setCursorImageOverride("left_ptr");
m_pWLRSurface = nullptr; m_pWLRSurface = nullptr;

View File

@@ -1,6 +1,9 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
class CWindow;
class CWLSurface { class CWLSurface {
public: public:
CWLSurface() = default; CWLSurface() = default;
@@ -17,6 +20,15 @@ class CWLSurface {
wlr_surface* wlr() const; wlr_surface* wlr() const;
bool exists() 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;
// allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false;
// if present, means this is a base surface of a window. Cleaned on unassign()
CWindow* m_pOwner = nullptr;
CWLSurface& operator=(wlr_surface* pSurface) { CWLSurface& operator=(wlr_surface* pSurface) {
destroy(); destroy();
@@ -38,6 +50,10 @@ class CWLSurface {
return exists(); return exists();
} }
static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) {
return (CWLSurface*)pSurface->data;
}
private: private:
wlr_surface* m_pWLRSurface = nullptr; 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

@@ -40,7 +40,7 @@ CWorkspace::~CWorkspace() {
void CWorkspace::startAnim(bool in, bool left, bool instant) { 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;
if (ANIMSTYLE.find("slidefade") == 0) { if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
float movePerc = 100.f; float movePerc = 100.f;
@@ -54,7 +54,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
m_fAlpha.setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
if (ANIMSTYLE.find("slidefadevert") == 0) { if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) { if (in) {
m_fAlpha.setValueAndWarp(0.f); m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));

View File

@@ -4,8 +4,8 @@
#include <string> #include <string>
#include "../defines.hpp" #include "../defines.hpp"
enum eFullscreenMode : uint8_t enum eFullscreenMode : int8_t {
{ FULLSCREEN_INVALID = -1,
FULLSCREEN_FULL = 0, FULLSCREEN_FULL = 0,
FULLSCREEN_MAXIMIZED FULLSCREEN_MAXIMIZED
}; };
@@ -49,12 +49,12 @@ class CWorkspace {
bool m_bDefaultFloating = false; bool m_bDefaultFloating = false;
bool m_bDefaultPseudo = false; bool m_bDefaultPseudo = false;
// don't destroy in sanity check
bool m_bIndestructible = false;
// last monitor (used on reconnect) // last monitor (used on reconnect)
std::string m_szLastMonitor = ""; 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 startAnim(bool in, bool left, bool instant = false);
void setActive(bool on); 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.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_NONE);
m_fFadeOpacity.registerVar(); 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) if (!m_bIsCreated)
return; return;
@@ -13,7 +13,7 @@ CHyprError::CHyprError() {
m_bMonitorChanged = true; 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) if (!m_bIsCreated)
return; return;
@@ -154,7 +154,7 @@ void CHyprError::draw() {
const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor; 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.x = (int)PMONITOR->vecPosition.x;
m_bDamageBox.y = (int)PMONITOR->vecPosition.y; m_bDamageBox.y = (int)PMONITOR->vecPosition.y;

View File

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

View File

@@ -47,7 +47,6 @@ extern "C" {
#include <wlr/types/wlr_export_dmabuf_v1.h> #include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h> #include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h> #include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h> #include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_layer_shell_v1.h>
@@ -105,6 +104,8 @@ extern "C" {
#include <wlr/types/wlr_single_pixel_buffer_v1.h> #include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_idle_notify_v1.h> #include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_cursor_shape_v1.h> #include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_tearing_control_v1.h>
#include <wlr/util/box.h>
#include <libdrm/drm_fourcc.h> #include <libdrm/drm_fourcc.h>
@@ -145,3 +146,5 @@ extern "C" {
#endif #endif
#include "helpers/Vector2D.hpp" #include "helpers/Vector2D.hpp"
#include "helpers/Box.hpp"
#include "SharedDefs.hpp"

View File

@@ -4,15 +4,12 @@
void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) { void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) {
if (children[0]) { if (children[0]) {
const auto REVERSESPLITRATIO = 2.f - splitRatio;
static auto* const PSMARTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:smart_split")->intValue; 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 PPRESERVESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:preserve_split")->intValue;
static auto* const PFLMULT = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue; static auto* const PFLMULT = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
if (*PPRESERVESPLIT == 0 && *PSMARTSPLIT == 0) { if (*PPRESERVESPLIT == 0 && *PSMARTSPLIT == 0) {
splitTop = size.y * *PFLMULT > size.x; splitTop = box.h * *PFLMULT > box.w;
} }
if (verticalOverride == true) if (verticalOverride == true)
@@ -24,16 +21,14 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
if (SPLITSIDE) { if (SPLITSIDE) {
// split left/right // split left/right
children[0]->position = position; const float FIRSTSIZE = box.w / 2.0 * splitRatio;
children[0]->size = Vector2D(size.x / 2.f * splitRatio, size.y); children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h};
children[1]->position = Vector2D(position.x + size.x / 2.f * splitRatio, position.y); children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h};
children[1]->size = Vector2D(size.x / 2.f * REVERSESPLITRATIO, size.y);
} else { } else {
// split top/bottom // split top/bottom
children[0]->position = position; const float FIRSTSIZE = box.h / 2.0 * splitRatio;
children[0]->size = Vector2D(size.x, size.y / 2.f * splitRatio); children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE};
children[1]->position = Vector2D(position.x, position.y + size.y / 2.f * splitRatio); children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE};
children[1]->size = Vector2D(size.x, size.y / 2.f * REVERSESPLITRATIO);
} }
children[0]->recalcSizePosRecursive(force); children[0]->recalcSizePosRecursive(force);
@@ -110,16 +105,19 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
} }
// for gaps outer // for gaps outer
const bool DISPLAYLEFT = STICKS(pNode->position.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x); const bool DISPLAYLEFT = STICKS(pNode->box.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 DISPLAYRIGHT = STICKS(pNode->box.x + pNode->box.w, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y); const bool DISPLAYTOP = STICKS(pNode->box.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y); const bool DISPLAYBOTTOM = STICKS(pNode->box.y + pNode->box.h, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const auto PWINDOW = pNode->pWindow; const auto PWINDOW = pNode->pWindow;
// get specific gaps and rules for this workspace, // get specific gaps and rules for this workspace,
// if user specified them in config // if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID));
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return;
PWINDOW->updateSpecialRenderData(); PWINDOW->updateSpecialRenderData();
static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue; static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
@@ -135,8 +133,11 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
return; return;
} }
PWINDOW->m_vSize = pNode->size; CBox nodeBox = pNode->box;
PWINDOW->m_vPosition = pNode->position; nodeBox.round();
PWINDOW->m_vSize = nodeBox.size();
PWINDOW->m_vPosition = nodeBox.pos();
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID); const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID);
@@ -157,6 +158,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
return; return;
} }
@@ -204,10 +207,13 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
// if special, we adjust the coords a bit // if special, we adjust the coords a bit
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue; static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue;
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f; CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
PWINDOW->m_vRealSize = 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 { } else {
PWINDOW->m_vRealSize = calcSize; PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos; PWINDOW->m_vRealPosition = calcPos;
@@ -282,7 +288,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
} }
// first, check if OPENINGON isn't too big. // 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) { if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) {
// we can't continue. make it floating. // we can't continue. make it floating.
pWindow->m_bIsFloating = true; pWindow->m_bIsFloating = true;
@@ -291,13 +297,6 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
return; 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 // last fail-safe to avoid duplicate fullscreens
if ((!OPENINGON || OPENINGON->pWindow == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) { if ((!OPENINGON || OPENINGON->pWindow == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) {
for (auto& node : m_lDwindleNodesData) { for (auto& node : m_lDwindleNodesData) {
@@ -310,8 +309,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
// if it's the first, it's easy. Make it fullscreen. // if it's the first, it's easy. Make it fullscreen.
if (!OPENINGON || OPENINGON->pWindow == pWindow) { if (!OPENINGON || OPENINGON->pWindow == pWindow) {
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; PNODE->box = CBox{PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
PNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
applyNodeDataToWindow(PNODE); applyNodeDataToWindow(PNODE);
@@ -320,39 +318,35 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
return; 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 it's a group, add the window
if (OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group if (OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
&& !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged && pWindow->canBeGroupedInto(OPENINGON->pWindow) && !m_vOverrideFocalPoint) { // we are not moving window
&& ((pWindow->m_eGroupRules & GROUP_INVADE && pWindow->m_bFirstMap) // window ignore local group locks, or
|| (!OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked // target unlocked
&& !(pWindow->m_sGroupData.pNextWindow && pWindow->getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group
&& !pWindow->m_sGroupData.deny // source is not denied entry
&& !(pWindow->m_eGroupRules & GROUP_BARRED && pWindow->m_bFirstMap) // group rule doesn't prevent adding window
&& !m_vOverrideFocalPoint // we are not moving window
) {
if (!pWindow->m_sGroupData.pNextWindow)
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
m_lDwindleNodesData.remove(*PNODE); m_lDwindleNodesData.remove(*PNODE);
const wlr_box box = OPENINGON->pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
if (wlr_box_contains_point(&box, MOUSECOORDS.x, MOUSECOORDS.y)) { // TODO: Deny when not using mouse
const int SIZE = OPENINGON->pWindow->getGroupSize();
const int INDEX = (int)((MOUSECOORDS.x - box.x) * 2 * SIZE / box.width + 1) / 2 - 1;
CWindow* pWindowInsertAfter = OPENINGON->pWindow->getGroupWindowByIndex(INDEX);
pWindowInsertAfter->insertWindowToGroup(pWindow);
if (INDEX == -1)
std::swap(pWindow->m_sGroupData.pNextWindow->m_sGroupData.head, pWindow->m_sGroupData.head);
} else {
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("misc:group_insert_after_current")->intValue;
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); (*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
}
OPENINGON->pWindow->setGroupCurrent(pWindow); OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules(); pWindow->applyGroupRules();
pWindow->updateWindowDecos(); pWindow->updateWindowDecos();
recalculateWindow(pWindow); recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return; return;
} }
@@ -362,8 +356,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto NEWPARENT = &m_lDwindleNodesData.back(); const auto NEWPARENT = &m_lDwindleNodesData.back();
// make the parent have the OPENINGON's stats // make the parent have the OPENINGON's stats
NEWPARENT->position = OPENINGON->position; NEWPARENT->box = OPENINGON->box;
NEWPARENT->size = OPENINGON->size;
NEWPARENT->workspaceID = OPENINGON->workspaceID; NEWPARENT->workspaceID = OPENINGON->workspaceID;
NEWPARENT->pParent = OPENINGON->pParent; NEWPARENT->pParent = OPENINGON->pParent;
NEWPARENT->isNode = true; // it is a node NEWPARENT->isNode = true; // it is a node
@@ -372,7 +365,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto PWIDTHMULTIPLIER = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue; const auto PWIDTHMULTIPLIER = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
// if cursor over first child, make it first, etc // 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; NEWPARENT->splitTop = !SIDEBYSIDE;
static auto* const PFORCESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:force_split")->intValue; static auto* const PFORCESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:force_split")->intValue;
@@ -404,11 +397,11 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
if (*PERMANENTDIRECTIONOVERRIDE == 0) if (*PERMANENTDIRECTIONOVERRIDE == 0)
overrideDirection = DIRECTION_DEFAULT; overrideDirection = DIRECTION_DEFAULT;
} else if (*PSMARTSPLIT == 1) { } else if (*PSMARTSPLIT == 1) {
const auto tl = NEWPARENT->position; const auto tl = NEWPARENT->box.pos();
const auto tr = NEWPARENT->position + Vector2D(NEWPARENT->size.x, 0); const auto tr = NEWPARENT->box.pos() + Vector2D(NEWPARENT->box.w, 0);
const auto bl = NEWPARENT->position + Vector2D(0, NEWPARENT->size.y); const auto bl = NEWPARENT->box.pos() + Vector2D(0, NEWPARENT->box.h);
const auto br = NEWPARENT->position + NEWPARENT->size; const auto br = NEWPARENT->box.pos() + NEWPARENT->box.size();
const auto cc = NEWPARENT->position + NEWPARENT->size / 2; const auto cc = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
if (MOUSECOORDS.inTriangle(tl, tr, cc)) { if (MOUSECOORDS.inTriangle(tl, tr, cc)) {
NEWPARENT->splitTop = true; NEWPARENT->splitTop = true;
@@ -429,11 +422,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
} }
} else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) { } else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
if ((SIDEBYSIDE && if ((SIDEBYSIDE &&
VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / *PWIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x / 2.f, VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
NEWPARENT->position.y + NEWPARENT->size.y)) ||
(!SIDEBYSIDE && (!SIDEBYSIDE &&
VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / *PWIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x, VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
NEWPARENT->position.y + NEWPARENT->size.y / 2.f))) {
// we are hovering over the first node, make PNODE first. // we are hovering over the first node, make PNODE first.
NEWPARENT->children[1] = OPENINGON; NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[0] = PNODE; NEWPARENT->children[0] = PNODE;
@@ -462,18 +453,14 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
} }
// Update the children // 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 // split left/right -> forced
OPENINGON->position = NEWPARENT->position; OPENINGON->box = {NEWPARENT->box.pos(), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
OPENINGON->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y); PNODE->box = {Vector2D(NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
PNODE->position = Vector2D(NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y);
PNODE->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y);
} else { } else {
// split top/bottom // split top/bottom
OPENINGON->position = NEWPARENT->position; OPENINGON->box = {NEWPARENT->box.pos(), Vector2D(NEWPARENT->box.w, NEWPARENT->box.h / 2.f)};
OPENINGON->size = Vector2D(NEWPARENT->size.x, NEWPARENT->size.y / 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)};
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->pParent = NEWPARENT; OPENINGON->pParent = NEWPARENT;
@@ -481,8 +468,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride); NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride);
applyNodeDataToWindow(PNODE); recalculateMonitor(pWindow->m_iMonitorID);
applyNodeDataToWindow(OPENINGON);
pWindow->applyGroupRules(); pWindow->applyGroupRules();
} }
@@ -510,8 +497,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
const auto PSIBLING = PPARENT->children[0] == PNODE ? PPARENT->children[1] : PPARENT->children[0]; const auto PSIBLING = PPARENT->children[0] == PNODE ? PPARENT->children[1] : PPARENT->children[0];
PSIBLING->position = PPARENT->position; PSIBLING->box = PPARENT->box;
PSIBLING->size = PPARENT->size;
PSIBLING->pParent = PPARENT->pParent; PSIBLING->pParent = PPARENT->pParent;
if (PPARENT->pParent != nullptr) { if (PPARENT->pParent != nullptr) {
@@ -551,8 +537,7 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->specialWorkspaceID); const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->specialWorkspaceID);
if (TOPNODE && PMONITOR) { if (TOPNODE && PMONITOR) {
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
TOPNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
TOPNODE->recalcSizePosRecursive(); TOPNODE->recalcSizePosRecursive();
} }
} }
@@ -567,11 +552,11 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
} else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { } else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
SDwindleNodeData fakeNode; SDwindleNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW; fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = PWORKSPACE->m_iID; fakeNode.workspaceID = PWORKSPACE->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.position; PFULLWINDOW->m_vPosition = fakeNode.box.pos();
PFULLWINDOW->m_vSize = fakeNode.size; PFULLWINDOW->m_vSize = fakeNode.box.size();
fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode); applyNodeDataToWindow(&fakeNode);
} }
@@ -582,8 +567,7 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace); const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace);
if (TOPNODE && PMONITOR) { if (TOPNODE && PMONITOR) {
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
TOPNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
TOPNODE->recalcSizePosRecursive(); TOPNODE->recalcSizePosRecursive();
} }
} }
@@ -628,7 +612,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
m_PseudoDragFlags.started = true; m_PseudoDragFlags.started = true;
const auto pseudoSize = PWINDOW->m_vRealSize.goalv(); 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) { if (mouseOffset.x > 0 && mouseOffset.x < pseudoSize.x && mouseOffset.y > 0 && mouseOffset.y < pseudoSize.y) {
m_PseudoDragFlags.pseudo = true; m_PseudoDragFlags.pseudo = true;
@@ -651,8 +635,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
else else
PWINDOW->m_vPseudoSize.y -= pixResize.y * 2; 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.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->size.y); PWINDOW->m_vPseudoSize.y = std::clamp(PWINDOW->m_vPseudoSize.y, 30.0, PNODE->box.h);
PWINDOW->m_vLastFloatingSize = PWINDOW->m_vPseudoSize; PWINDOW->m_vLastFloatingSize = PWINDOW->m_vPseudoSize;
PNODE->recalcSizePosRecursive(*PANIMATE == 0); PNODE->recalcSizePosRecursive(*PANIMATE == 0);
@@ -699,30 +683,30 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
} }
if (PHOUTER) { 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) { if (PHINNER) {
const auto ORIGINAL = PHINNER->size.x; const auto ORIGINAL = PHINNER->box.w;
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
if (PHINNER->pParent->children[0] == PHINNER) 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 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); PHINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
} else } else
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
} }
if (PVOUTER) { 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) { if (PVINNER) {
const auto ORIGINAL = PVINNER->size.y; const auto ORIGINAL = PVINNER->box.h;
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
if (PVINNER->pParent->children[0] == PVINNER) 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 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); PVINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
} else } else
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0); PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
@@ -742,11 +726,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
// No parent means we have only 2 windows, and thus one axis of freedom // No parent means we have only 2 windows, and thus one axis of freedom
if (!PPARENT2) { if (!PPARENT2) {
if (PARENTSIDEBYSIDE) { 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->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0); PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else { } 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->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0); PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} }
@@ -761,11 +745,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
// no parent, one axis of freedom // no parent, one axis of freedom
if (!PPARENT2) { if (!PPARENT2) {
if (PARENTSIDEBYSIDE) { 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->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0); PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else { } 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->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0); PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} }
@@ -777,8 +761,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
const auto SIDECONTAINER = PARENTSIDEBYSIDE ? PPARENT : PPARENT2; const auto SIDECONTAINER = PARENTSIDEBYSIDE ? PPARENT : PPARENT2;
const auto TOPCONTAINER = PARENTSIDEBYSIDE ? PPARENT2 : PPARENT; const auto TOPCONTAINER = PARENTSIDEBYSIDE ? PPARENT2 : PPARENT;
allowedMovement.x *= 2.f / SIDECONTAINER->size.x; allowedMovement.x *= 2.f / SIDECONTAINER->box.w;
allowedMovement.y *= 2.f / TOPCONTAINER->size.y; allowedMovement.y *= 2.f / TOPCONTAINER->box.h;
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, 0.1, 1.9); SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, 0.1, 1.9);
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, 0.1, 1.9); TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, 0.1, 1.9);
@@ -846,11 +830,10 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
SDwindleNodeData fakeNode; SDwindleNodeData fakeNode;
fakeNode.pWindow = pWindow; fakeNode.pWindow = pWindow;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = pWindow->m_iWorkspaceID; fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.position; pWindow->m_vPosition = fakeNode.box.pos();
pWindow->m_vSize = fakeNode.size; pWindow->m_vSize = fakeNode.box.size();
applyNodeDataToWindow(&fakeNode); applyNodeDataToWindow(&fakeNode);
} }
@@ -962,17 +945,15 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
} }
if (ACTIVE1) { if (ACTIVE1) {
ACTIVE1->position = PNODE->position; ACTIVE1->box = PNODE->box;
ACTIVE1->size = PNODE->size; ACTIVE1->pWindow->m_vPosition = ACTIVE1->box.pos();
ACTIVE1->pWindow->m_vPosition = ACTIVE1->position; ACTIVE1->pWindow->m_vSize = ACTIVE1->box.size();
ACTIVE1->pWindow->m_vSize = ACTIVE1->size;
} }
if (ACTIVE2) { if (ACTIVE2) {
ACTIVE2->position = PNODE2->position; ACTIVE2->box = PNODE2->box;
ACTIVE2->size = PNODE2->size; ACTIVE2->pWindow->m_vPosition = ACTIVE2->box.pos();
ACTIVE2->pWindow->m_vPosition = ACTIVE2->position; ACTIVE2->pWindow->m_vSize = ACTIVE2->box.size();
ACTIVE2->pWindow->m_vSize = ACTIVE2->size;
} }
g_pHyprRenderer->damageWindow(pWindow); g_pHyprRenderer->damageWindow(pWindow);

View File

@@ -9,7 +9,7 @@
#include <format> #include <format>
class CHyprDwindleLayout; class CHyprDwindleLayout;
enum eFullscreenMode : uint8_t; enum eFullscreenMode : int8_t;
struct SDwindleNodeData { struct SDwindleNodeData {
SDwindleNodeData* pParent = nullptr; SDwindleNodeData* pParent = nullptr;
@@ -21,8 +21,7 @@ struct SDwindleNodeData {
bool splitTop = false; // for preserve_split bool splitTop = false; // for preserve_split
Vector2D position; CBox box = {0};
Vector2D size;
int workspaceID = -1; int workspaceID = -1;
@@ -30,10 +29,12 @@ struct SDwindleNodeData {
bool valid = true; bool valid = true;
bool ignoreFullscreenChecks = false;
// For list lookup // For list lookup
bool operator==(const SDwindleNodeData& rhs) const { bool operator==(const SDwindleNodeData& rhs) const {
return pWindow == rhs.pWindow && workspaceID == rhs.workspaceID && position == rhs.position && size == rhs.size && pParent == rhs.pParent && return pWindow == rhs.pWindow && workspaceID == rhs.workspaceID && box == rhs.box && pParent == rhs.pParent && children[0] == rhs.children[0] &&
children[0] == rhs.children[0] && children[1] == rhs.children[1]; children[1] == rhs.children[1];
} }
void recalcSizePosRecursive(bool force = false, bool horizontalOverride = false, bool verticalOverride = false); void recalcSizePosRecursive(bool force = false, bool horizontalOverride = false, bool verticalOverride = false);
@@ -94,7 +95,7 @@ struct std::formatter<SDwindleNodeData*, CharT> : std::formatter<CharT> {
auto out = ctx.out(); auto out = ctx.out();
if (!node) if (!node)
return std::format_to(out, "[Node nullptr]"); return std::format_to(out, "[Node nullptr]");
std::format_to(out, "[Node {:x}: workspace: {}, pos: {:j2}, size: {:j2}", (uintptr_t)node, node->workspaceID, node->position, node->size); 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) if (!node->isNode && node->pWindow)
std::format_to(out, ", window: {:x}", node->pWindow); std::format_to(out, ", window: {:x}", node->pWindow);
return std::format_to(out, "]"); return std::format_to(out, "]");

View File

@@ -6,7 +6,7 @@ void IHyprLayout::onWindowCreated(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) { if (pWindow->m_bIsFloating) {
onWindowCreatedFloating(pWindow); onWindowCreatedFloating(pWindow);
} else { } else {
wlr_box desiredGeometry = {0}; CBox desiredGeometry = {};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) {
@@ -75,7 +75,7 @@ void IHyprLayout::onWindowRemovedFloating(CWindow* pWindow) {
void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) { void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
wlr_box desiredGeometry = {0}; CBox desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -162,6 +162,9 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pCompositor->changeWindowZOrder(pWindow, true); g_pCompositor->changeWindowZOrder(pWindow, true);
} else {
pWindow->m_vPendingReportedSize = pWindow->m_vRealSize.goalv();
pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize;
} }
} }
@@ -254,6 +257,7 @@ void IHyprLayout::onEndDragWindow() {
g_pInputManager->unsetCursorImage(); g_pInputManager->unsetCursorImage();
g_pInputManager->currentlyDraggedWindow = nullptr; g_pInputManager->currentlyDraggedWindow = nullptr;
g_pInputManager->m_bWasDraggingWindow = true;
if (DRAGGINGWINDOW->m_bDraggingTiled) { if (DRAGGINGWINDOW->m_bDraggingTiled) {
DRAGGINGWINDOW->m_bIsFloating = false; DRAGGINGWINDOW->m_bIsFloating = false;
@@ -265,6 +269,8 @@ void IHyprLayout::onEndDragWindow() {
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
g_pCompositor->focusWindow(DRAGGINGWINDOW); g_pCompositor->focusWindow(DRAGGINGWINDOW);
g_pInputManager->m_bWasDraggingWindow = false;
} }
void IHyprLayout::onMouseMove(const Vector2D& mousePos) { void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
@@ -301,11 +307,13 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (g_pInputManager->dragMode == MBIND_MOVE) { if (g_pInputManager->dragMode == MBIND_MOVE) {
if (*PANIMATEMOUSE) { CBox wb = {m_vBeginDragPositionXY + DELTA, DRAGGINGWINDOW->m_vRealSize.goalv()};
DRAGGINGWINDOW->m_vRealPosition = m_vBeginDragPositionXY + DELTA; wb.round();
} else {
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(m_vBeginDragPositionXY + DELTA); if (*PANIMATEMOUSE)
} DRAGGINGWINDOW->m_vRealPosition = wb.pos();
else
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos());
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); 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) { } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) {
@@ -357,12 +365,15 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT)
newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0); newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0);
CBox wb = {newPos, newSize};
wb.round();
if (*PANIMATE) { if (*PANIMATE) {
DRAGGINGWINDOW->m_vRealSize = newSize; DRAGGINGWINDOW->m_vRealSize = wb.size();
DRAGGINGWINDOW->m_vRealPosition = newPos; DRAGGINGWINDOW->m_vRealPosition = wb.pos();
} else { } else {
DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(newSize); DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(wb.size());
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(newPos); DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos());
} }
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
@@ -408,7 +419,7 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
if (!TILED) { if (!TILED) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f); const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID; pWindow->m_iMonitorID = PNEWMON->ID;
pWindow->moveToWorkspace(PNEWMON->activeWorkspace); pWindow->moveToWorkspace(PNEWMON->specialWorkspaceID != 0 ? PNEWMON->specialWorkspaceID : PNEWMON->activeWorkspace);
pWindow->updateGroupOutputs(); pWindow->updateGroupOutputs();
// save real pos cuz the func applies the default 5,5 mid // save real pos cuz the func applies the default 5,5 mid

View File

@@ -13,9 +13,10 @@ struct SLayoutMessageHeader {
CWindow* pWindow = nullptr; CWindow* pWindow = nullptr;
}; };
enum eFullscreenMode : uint8_t; enum eFullscreenMode : int8_t;
enum eRectCorner { enum eRectCorner
{
CORNER_NONE = 0, CORNER_NONE = 0,
CORNER_TOPLEFT, CORNER_TOPLEFT,
CORNER_TOPRIGHT, CORNER_TOPRIGHT,
@@ -23,7 +24,8 @@ enum eRectCorner {
CORNER_BOTTOMLEFT CORNER_BOTTOMLEFT
}; };
enum eDirection { enum eDirection
{
DIRECTION_DEFAULT = -1, DIRECTION_DEFAULT = -1,
DIRECTION_UP = 0, DIRECTION_UP = 0,
DIRECTION_RIGHT, DIRECTION_RIGHT,

View File

@@ -94,45 +94,106 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
if (g_pInputManager->m_bWasDraggingWindow && OPENINGON) {
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 it's a group, add the window
if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
&& !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged && pWindow->canBeGroupedInto(OPENINGON->pWindow)) {
&& ((pWindow->m_eGroupRules & GROUP_INVADE && pWindow->m_bFirstMap) // window ignore local group locks, or
|| (!OPENINGON->pWindow->getGroupHead()->m_sGroupData.locked // target unlocked
&& !(pWindow->m_sGroupData.pNextWindow && pWindow->getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group
&& !pWindow->m_sGroupData.deny // source is not denied entry
&& !(pWindow->m_eGroupRules & GROUP_BARRED) // group rule doesn't prevent adding window
) {
if (!pWindow->m_sGroupData.pNextWindow)
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
m_lMasterNodesData.remove(*PNODE); m_lMasterNodesData.remove(*PNODE);
const wlr_box box = OPENINGON->pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
if (wlr_box_contains_point(&box, MOUSECOORDS.x, MOUSECOORDS.y)) { // TODO: Deny when not using mouse
const int SIZE = OPENINGON->pWindow->getGroupSize();
const int INDEX = (int)((MOUSECOORDS.x - box.x) * 2 * SIZE / box.width + 1) / 2 - 1;
CWindow* pWindowInsertAfter = OPENINGON->pWindow->getGroupWindowByIndex(INDEX);
pWindowInsertAfter->insertWindowToGroup(pWindow);
if (INDEX == -1)
std::swap(pWindow->m_sGroupData.pNextWindow->m_sGroupData.head, pWindow->m_sGroupData.head);
} else {
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("misc:group_insert_after_current")->intValue;
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); (*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
}
OPENINGON->pWindow->setGroupCurrent(pWindow); OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules(); pWindow->applyGroupRules();
pWindow->updateWindowDecos(); pWindow->updateWindowDecos();
recalculateWindow(pWindow); recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return; return;
} }
pWindow->applyGroupRules(); pWindow->applyGroupRules();
if (*PNEWISMASTER || WINDOWSONWORKSPACE == 1 || (!pWindow->m_bFirstMap && OPENINGON->isMaster)) { 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) { for (auto& nd : m_lMasterNodesData) {
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
nd.isMaster = false; nd.isMaster = false;
@@ -167,13 +228,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
} }
} }
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
}
// recalc // recalc
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->m_iMonitorID);
} }
@@ -575,6 +629,9 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
// if user specified them in config // if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID));
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return;
PWINDOW->updateSpecialRenderData(); PWINDOW->updateSpecialRenderData();
static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue; static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
@@ -611,6 +668,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
return; return;
} }
@@ -633,15 +692,21 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) { if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue; static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue;
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f; CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
PWINDOW->m_vRealSize = 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 { } else {
PWINDOW->m_vRealSize = calcSize; CBox wb = {calcPos, calcSize};
PWINDOW->m_vRealPosition = calcPos; 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 && !*PANIMATE) { if (m_bForceWarps && !*PANIMATE) {
@@ -718,8 +783,9 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
default: UNREACHABLE(); default: UNREACHABLE();
} }
const auto workspaceIdForResizing = PMONITOR->specialWorkspaceID == 0 ? PMONITOR->activeWorkspace : PMONITOR->specialWorkspaceID;
for (auto& n : m_lMasterNodesData) { 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); n.percMaster = std::clamp(n.percMaster + delta, 0.05, 0.95);
} }
@@ -866,6 +932,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
fakeNode.workspaceID = pWindow->m_iWorkspaceID; fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.position; pWindow->m_vPosition = fakeNode.position;
pWindow->m_vSize = fakeNode.size; pWindow->m_vSize = fakeNode.size;
fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode); applyNodeDataToWindow(&fakeNode);
} }
@@ -903,7 +970,16 @@ void CHyprMasterLayout::moveWindowTo(CWindow* pWindow, const std::string& dir) {
const auto PWINDOW2 = g_pCompositor->getWindowInDirection(pWindow, dir[0]); 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); switchWindows(pWindow, PWINDOW2);
}
} }
void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) { void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {

View File

@@ -7,7 +7,7 @@
#include <deque> #include <deque>
#include <any> #include <any>
enum eFullscreenMode : uint8_t; enum eFullscreenMode : int8_t;
//orientation determines which side of the screen the master area resides //orientation determines which side of the screen the master area resides
enum eOrientation : uint8_t { enum eOrientation : uint8_t {
@@ -31,6 +31,9 @@ struct SMasterNodeData {
int workspaceID = -1; int workspaceID = -1;
bool ignoreFullscreenChecks = false;
//
bool operator==(const SMasterNodeData& rhs) const { bool operator==(const SMasterNodeData& rhs) const {
return pWindow == rhs.pWindow; return pWindow == rhs.pWindow;
} }
@@ -40,6 +43,7 @@ struct SMasterWorkspaceData {
int workspaceID = -1; int workspaceID = -1;
eOrientation orientation = ORIENTATION_LEFT; eOrientation orientation = ORIENTATION_LEFT;
//
bool operator==(const SMasterWorkspaceData& rhs) const { bool operator==(const SMasterWorkspaceData& rhs) const {
return workspaceID == rhs.workspaceID; return workspaceID == rhs.workspaceID;
} }

View File

@@ -14,22 +14,7 @@
#define ISDEBUG false #define ISDEBUG false
#endif #endif
// git stuff #include "version.h"
#ifndef GIT_COMMIT_HASH
#define GIT_COMMIT_HASH "?"
#endif
#ifndef GIT_BRANCH
#define GIT_BRANCH "?"
#endif
#ifndef GIT_COMMIT_MESSAGE
#define GIT_COMMIT_MESSAGE "?"
#endif
#ifndef GIT_DIRTY
#define GIT_DIRTY "?"
#endif
#ifndef GIT_TAG
#define GIT_TAG "?"
#endif
#define SPECIAL_WORKSPACE_START (-99) #define SPECIAL_WORKSPACE_START (-99)
@@ -57,7 +42,7 @@
if (!(expr)) { \ if (!(expr)) { \
Debug::log(CRIT, "\n==========================================================================================\nASSERTION FAILED! \n\n{}\n\nat: line {} in {}", \ Debug::log(CRIT, "\n==========================================================================================\nASSERTION FAILED! \n\n{}\n\nat: line {} in {}", \
std::format(reason, ##__VA_ARGS__), __LINE__, \ std::format(reason, ##__VA_ARGS__), __LINE__, \
([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })()); \ ([]() constexpr->std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })()); \
printf("Assertion failed! See the log in /tmp/hypr/hyprland.log for more info."); \ printf("Assertion failed! See the log in /tmp/hypr/hyprland.log for more info."); \
raise(SIGABRT); \ raise(SIGABRT); \
} }
@@ -76,7 +61,9 @@
} }
#define FORMAT_FLAG(spec__, flag__) \ #define FORMAT_FLAG(spec__, flag__) \
case spec__: (flag__) = true; break; case spec__: \
(flag__) = true; \
break;
#define FORMAT_NUMBER(buf__) \ #define FORMAT_NUMBER(buf__) \
case '0': \ case '0': \
@@ -88,7 +75,9 @@
case '6': \ case '6': \
case '7': \ case '7': \
case '8': \ case '8': \
case '9': (buf__).push_back(*it); break; case '9': \
(buf__).push_back(*it); \
break;
#if ISDEBUG #if ISDEBUG
#define UNREACHABLE() \ #define UNREACHABLE() \

View File

@@ -104,6 +104,8 @@ int main(int argc, char** argv) {
// If all's good to go, start. // If all's good to go, start.
g_pCompositor->startCompositor(); g_pCompositor->startCompositor();
g_pCompositor->m_bIsShuttingDown = true;
// If we are here it means we got yote. // If we are here it means we got yote.
Debug::log(LOG, "Hyprland reached the end."); Debug::log(LOG, "Hyprland reached the end.");
g_pCompositor.reset(); g_pCompositor.reset();

View File

@@ -68,6 +68,7 @@ void CAnimationManager::tick() {
if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) { if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) {
av->warp(false); av->warp(false);
animationEndedVars.push_back(av);
continue; continue;
} }
@@ -81,7 +82,7 @@ void CAnimationManager::tick() {
CMonitor* PMONITOR = nullptr; CMonitor* PMONITOR = nullptr;
bool animationsDisabled = animGlobalDisabled; bool animationsDisabled = animGlobalDisabled;
wlr_box WLRBOXPREV = {0, 0, 0, 0}; CBox WLRBOXPREV = {0, 0, 0, 0};
if (PWINDOW) { if (PWINDOW) {
WLRBOXPREV = PWINDOW->getFullWindowBoundingBox(); WLRBOXPREV = PWINDOW->getFullWindowBoundingBox();
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
@@ -93,6 +94,12 @@ void CAnimationManager::tick() {
if (!PMONITOR) if (!PMONITOR)
continue; continue;
WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y}; WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y};
// TODO: just make this into a damn callback already vax...
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->isHidden() && w->m_bIsMapped && w->m_bIsFloating)
g_pHyprRenderer->damageWindow(w.get());
}
} else if (PLAYER) { } else if (PLAYER) {
WLRBOXPREV = PLAYER->geometry; WLRBOXPREV = PLAYER->geometry;
PMONITOR = g_pCompositor->getMonitorFromVector(Vector2D(PLAYER->geometry.x, PLAYER->geometry.y) + Vector2D(PLAYER->geometry.width, PLAYER->geometry.height) / 2.f); PMONITOR = g_pCompositor->getMonitorFromVector(Vector2D(PLAYER->geometry.x, PLAYER->geometry.y) + Vector2D(PLAYER->geometry.width, PLAYER->geometry.height) / 2.f);
@@ -230,7 +237,7 @@ void CAnimationManager::tick() {
BORDERSIZE + ROUNDINGSIZE); // bottom BORDERSIZE + ROUNDINGSIZE); // bottom
// damage for new box // damage for new box
const wlr_box WLRBOXNEW = {PWINDOW->m_vRealPosition.vec().x, PWINDOW->m_vRealPosition.vec().y, PWINDOW->m_vRealSize.vec().x, PWINDOW->m_vRealSize.vec().y}; const CBox WLRBOXNEW = {PWINDOW->m_vRealPosition.vec().x, PWINDOW->m_vRealPosition.vec().y, PWINDOW->m_vRealSize.vec().x, PWINDOW->m_vRealSize.vec().y};
g_pHyprRenderer->damageBox(WLRBOXNEW.x - BORDERSIZE, WLRBOXNEW.y - BORDERSIZE, WLRBOXNEW.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // top g_pHyprRenderer->damageBox(WLRBOXNEW.x - BORDERSIZE, WLRBOXNEW.y - BORDERSIZE, WLRBOXNEW.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // top
g_pHyprRenderer->damageBox(WLRBOXNEW.x - BORDERSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, WLRBOXNEW.height + 2 * BORDERSIZE); // left g_pHyprRenderer->damageBox(WLRBOXNEW.x - BORDERSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, WLRBOXNEW.height + 2 * BORDERSIZE); // left
g_pHyprRenderer->damageBox(WLRBOXNEW.x + WLRBOXNEW.width - ROUNDINGSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, g_pHyprRenderer->damageBox(WLRBOXNEW.x + WLRBOXNEW.width - ROUNDINGSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE,
@@ -242,29 +249,9 @@ void CAnimationManager::tick() {
case AVARDAMAGE_SHADOW: { case AVARDAMAGE_SHADOW: {
RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!"); RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!");
static auto* const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW);
if (PDECO) { PDECO->damageEntire();
const auto EXTENTS = PDECO->getWindowDecorationExtents();
wlr_box dmg = {PWINDOW->m_vRealPosition.vec().x - EXTENTS.topLeft.x, PWINDOW->m_vRealPosition.vec().y - EXTENTS.topLeft.y,
PWINDOW->m_vRealSize.vec().x + EXTENTS.topLeft.x + EXTENTS.bottomRight.x,
PWINDOW->m_vRealSize.vec().y + EXTENTS.topLeft.y + EXTENTS.bottomRight.y};
if (!*PSHADOWIGNOREWINDOW) {
// easy, damage the entire box
g_pHyprRenderer->damageBox(&dmg);
} else {
CRegion rg{dmg.x, dmg.y, dmg.width, dmg.height};
CRegion wb{PWINDOW->m_vRealPosition.vec().x, PWINDOW->m_vRealPosition.vec().y, PWINDOW->m_vRealSize.vec().x, PWINDOW->m_vRealSize.vec().y};
rg.subtract(wb);
g_pHyprRenderer->damageRegion(rg);
}
}
break; break;
} }
@@ -423,7 +410,7 @@ void CAnimationManager::onWindowPostCreateClose(CWindow* pWindow, bool close) {
if (pWindow->m_sAdditionalConfigData.animationStyle != "") { if (pWindow->m_sAdditionalConfigData.animationStyle != "") {
// the window has config'd special anim // the window has config'd special anim
if (pWindow->m_sAdditionalConfigData.animationStyle.find("slide") == 0) { if (pWindow->m_sAdditionalConfigData.animationStyle.starts_with("slide")) {
if (pWindow->m_sAdditionalConfigData.animationStyle.contains(' ')) { if (pWindow->m_sAdditionalConfigData.animationStyle.contains(' ')) {
// has a direction // has a direction
animationSlide(pWindow, pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find(' ') + 1), close); animationSlide(pWindow, pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find(' ') + 1), close);
@@ -452,7 +439,7 @@ void CAnimationManager::onWindowPostCreateClose(CWindow* pWindow, bool close) {
// anim popin, fallback // anim popin, fallback
float minPerc = 0.f; float minPerc = 0.f;
if (ANIMSTYLE.find("%") != 0) { if (!ANIMSTYLE.starts_with("%")) {
try { try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ')); auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
@@ -467,10 +454,10 @@ void CAnimationManager::onWindowPostCreateClose(CWindow* pWindow, bool close) {
} }
std::string CAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { std::string CAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) {
if (config.find("window") == 0) { if (config.starts_with("window")) {
if (style == "slide") { if (style == "slide") {
return ""; return "";
} else if (style.find("popin") == 0) { } else if (style.starts_with("popin")) {
// try parsing // try parsing
float minPerc = 0.f; float minPerc = 0.f;
if (style.find("%") != std::string::npos) { if (style.find("%") != std::string::npos) {
@@ -491,7 +478,7 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config,
} else if (config == "workspaces" || config == "specialWorkspace") { } else if (config == "workspaces" || config == "specialWorkspace") {
if (style == "slide" || style == "slidevert" || style == "fade") if (style == "slide" || style == "slidevert" || style == "fade")
return ""; return "";
else if (style.find("slidefade") == 0) { else if (style.starts_with("slidefade")) {
// try parsing // try parsing
float movePerc = 0.f; float movePerc = 0.f;
if (style.find("%") != std::string::npos) { if (style.find("%") != std::string::npos) {

View File

@@ -26,7 +26,7 @@ void CHookSystemManager::unhook(HOOK_CALLBACK_FN* fn) {
} }
} }
void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, std::any data) { void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, SCallbackInfo& info, std::any data) {
if (callbacks->empty()) if (callbacks->empty())
return; return;
@@ -38,7 +38,7 @@ void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, std:
if (!cb.handle) { if (!cb.handle) {
// we don't guard hl hooks // we don't guard hl hooks
(*cb.fn)(cb.fn, data); (*cb.fn)(cb.fn, info, data);
continue; continue;
} }
@@ -49,7 +49,7 @@ void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, std:
try { try {
if (!setjmp(m_jbHookFaultJumpBuf)) if (!setjmp(m_jbHookFaultJumpBuf))
(*cb.fn)(cb.fn, data); (*cb.fn)(cb.fn, info, data);
else { else {
// this module crashed. // this module crashed.
throw std::exception(); throw std::exception();

View File

@@ -12,7 +12,8 @@
#include "../plugins/PluginAPI.hpp" #include "../plugins/PluginAPI.hpp"
// global typedef for hooked functions. Passes itself as a ptr when called, and `data` additionally. // global typedef for hooked functions. Passes itself as a ptr when called, and `data` additionally.
typedef std::function<void(void*, std::any)> HOOK_CALLBACK_FN;
typedef std::function<void(void*, SCallbackInfo& info, std::any data)> HOOK_CALLBACK_FN;
struct SCallbackFNPtr { struct SCallbackFNPtr {
HOOK_CALLBACK_FN* fn = nullptr; HOOK_CALLBACK_FN* fn = nullptr;
@@ -22,7 +23,17 @@ struct SCallbackFNPtr {
#define EMIT_HOOK_EVENT(name, param) \ #define EMIT_HOOK_EVENT(name, param) \
{ \ { \
static auto* const PEVENTVEC = g_pHookSystem->getVecForEvent(name); \ static auto* const PEVENTVEC = g_pHookSystem->getVecForEvent(name); \
g_pHookSystem->emit(PEVENTVEC, param); \ SCallbackInfo info; \
g_pHookSystem->emit(PEVENTVEC, info, param); \
}
#define EMIT_HOOK_EVENT_CANCELLABLE(name, param) \
{ \
static auto* const PEVENTVEC = g_pHookSystem->getVecForEvent(name); \
SCallbackInfo info; \
g_pHookSystem->emit(PEVENTVEC, info, param); \
if (info.cancelled) \
return; \
} }
class CHookSystemManager { class CHookSystemManager {
@@ -34,7 +45,7 @@ class CHookSystemManager {
void hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn, HANDLE handle = nullptr); void hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn, HANDLE handle = nullptr);
void unhook(HOOK_CALLBACK_FN* fn); void unhook(HOOK_CALLBACK_FN* fn);
void emit(const std::vector<SCallbackFNPtr>* callbacks, std::any data = 0); void emit(const std::vector<SCallbackFNPtr>* callbacks, SCallbackInfo& info, std::any data = 0);
std::vector<SCallbackFNPtr>* getVecForEvent(const std::string& event); std::vector<SCallbackFNPtr>* getVecForEvent(const std::string& event);
bool m_bCurrentEventPlugin = false; bool m_bCurrentEventPlugin = false;

View File

@@ -1,5 +1,7 @@
#include "KeybindManager.hpp" #include "KeybindManager.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "debug/Log.hpp"
#include "helpers/VarList.hpp"
#include <regex> #include <regex>
@@ -77,7 +79,7 @@ CKeybindManager::CKeybindManager() {
m_tScrollTimer.reset(); m_tScrollTimer.reset();
g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, std::any param) { g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) {
// clear cuz realloc'd // clear cuz realloc'd
m_pActiveKeybind = nullptr; m_pActiveKeybind = nullptr;
m_vPressedSpecialBinds.clear(); m_vPressedSpecialBinds.clear();
@@ -435,7 +437,8 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
const bool IGNORECONDITIONS = const bool IGNORECONDITIONS =
SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released. SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released.
if (!IGNORECONDITIONS && (modmask != k.modmask || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap || k.shadowed)) if (!IGNORECONDITIONS &&
((modmask != k.modmask && !k.ignoreMods) || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap || k.shadowed))
continue; continue;
if (!key.empty()) { if (!key.empty()) {
@@ -804,12 +807,13 @@ void CKeybindManager::changeworkspace(std::string args) {
// the current workspace will instead switch to the previous. // the current workspace will instead switch to the previous.
static auto* const PBACKANDFORTH = &g_pConfigManager->getConfigValuePtr("binds:workspace_back_and_forth")->intValue; static auto* const PBACKANDFORTH = &g_pConfigManager->getConfigValuePtr("binds:workspace_back_and_forth")->intValue;
static auto* const PALLOWWORKSPACECYCLES = &g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles")->intValue; static auto* const PALLOWWORKSPACECYCLES = &g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles")->intValue;
static auto* const PWORKSPACECENTERON = &g_pConfigManager->getConfigValuePtr("binds:workspace_center_on")->intValue;
const auto PMONITOR = g_pCompositor->m_pLastMonitor; const auto PMONITOR = g_pCompositor->m_pLastMonitor;
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
const bool EXPLICITPREVIOUS = args.find("previous") == 0; const bool EXPLICITPREVIOUS = args.starts_with("previous");
if (args.find("previous") == 0) { if (args.starts_with("previous")) {
// Do nothing if there's no previous workspace, otherwise switch to it. // Do nothing if there's no previous workspace, otherwise switch to it.
if (PCURRENTWORKSPACE->m_sPrevWorkspace.iID == -1) { if (PCURRENTWORKSPACE->m_sPrevWorkspace.iID == -1) {
Debug::log(LOG, "No previous workspace to change to"); Debug::log(LOG, "No previous workspace to change to");
@@ -863,9 +867,13 @@ void CKeybindManager::changeworkspace(std::string args) {
PMONITORWORKSPACEOWNER->changeWorkspace(pWorkspaceToChangeTo, false, true); PMONITORWORKSPACEOWNER->changeWorkspace(pWorkspaceToChangeTo, false, true);
if (PMONITOR != PMONITORWORKSPACEOWNER) { if (PMONITOR != PMONITORWORKSPACEOWNER) {
g_pCompositor->warpCursorTo(PMONITORWORKSPACEOWNER->middle()); Vector2D middle = PMONITORWORKSPACEOWNER->middle();
if (const auto PLAST = pWorkspaceToChangeTo->getLastFocusedWindow(); PLAST) if (const auto PLAST = pWorkspaceToChangeTo->getLastFocusedWindow(); PLAST) {
g_pCompositor->focusWindow(PLAST); g_pCompositor->focusWindow(PLAST);
if (*PWORKSPACECENTERON == 1)
middle = PLAST->middle();
}
g_pCompositor->warpCursorTo(middle);
} }
if (BISWORKSPACECURRENT) { if (BISWORKSPACECURRENT) {
@@ -996,6 +1004,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
} }
void CKeybindManager::moveFocusTo(std::string args) { void CKeybindManager::moveFocusTo(std::string args) {
static auto* const PFULLCYCLE = &g_pConfigManager->getConfigValuePtr("binds:movefocus_cycles_fullscreen")->intValue;
char arg = args[0]; char arg = args[0];
if (!isDirection(args)) { if (!isDirection(args)) {
@@ -1012,7 +1021,7 @@ void CKeybindManager::moveFocusTo(std::string args) {
// remove constraints // remove constraints
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
const auto PWINDOWTOCHANGETO = PLASTWINDOW->m_bIsFullscreen ? const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->m_bIsFullscreen ?
(arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) : (arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) :
g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
@@ -1083,13 +1092,13 @@ void CKeybindManager::swapActive(std::string args) {
return; return;
g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, PWINDOWTOCHANGETO); g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, PWINDOWTOCHANGETO);
g_pCompositor->warpCursorTo(PLASTWINDOW->m_vRealPosition.vec() + PLASTWINDOW->m_vRealSize.vec() / 2.0); g_pCompositor->warpCursorTo(PLASTWINDOW->middle());
} }
void CKeybindManager::moveActiveTo(std::string args) { void CKeybindManager::moveActiveTo(std::string args) {
char arg = args[0]; char arg = args[0];
if (args.find("mon:") == 0) { if (args.starts_with("mon:")) {
const auto PNEWMONITOR = g_pCompositor->getMonitorFromString(args.substr(4)); const auto PNEWMONITOR = g_pCompositor->getMonitorFromString(args.substr(4));
if (!PNEWMONITOR) if (!PNEWMONITOR)
return; return;
@@ -1109,20 +1118,20 @@ void CKeybindManager::moveActiveTo(std::string args) {
return; return;
if (PLASTWINDOW->m_bIsFloating) { if (PLASTWINDOW->m_bIsFloating) {
auto vPos = PLASTWINDOW->m_vRealPosition.goalv(); Vector2D vPos;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PLASTWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PLASTWINDOW->m_iMonitorID);
const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize(); const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize();
switch (arg) { switch (arg) {
case 'l': vPos.x = PMONITOR->vecReservedTopLeft.x + BORDERSIZE; break; case 'l': vPos.x = PMONITOR->vecReservedTopLeft.x + BORDERSIZE + PMONITOR->vecPosition.x; break;
case 'r': vPos.x = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize.goalv().x - BORDERSIZE; break; case 'r': vPos.x = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize.goalv().x - BORDERSIZE + PMONITOR->vecPosition.x; break;
case 't': case 't':
case 'u': vPos.y = PMONITOR->vecReservedTopLeft.y + BORDERSIZE; break; case 'u': vPos.y = PMONITOR->vecReservedTopLeft.y + BORDERSIZE + PMONITOR->vecPosition.y; break;
case 'b': case 'b':
case 'd': vPos.y = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize.goalv().y - BORDERSIZE; break; case 'd': vPos.y = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize.goalv().y - BORDERSIZE + PMONITOR->vecPosition.y; break;
} }
PLASTWINDOW->m_vRealPosition = vPos + PMONITOR->vecPosition; PLASTWINDOW->m_vRealPosition = Vector2D(vPos.x != 0 ? vPos.x : PLASTWINDOW->m_vRealPosition.goalv().x, vPos.y != 0 ? vPos.y : PLASTWINDOW->m_vRealPosition.goalv().y);
return; return;
} }
@@ -1172,6 +1181,18 @@ void CKeybindManager::changeGroupActive(std::string args) {
if (PWINDOW->m_sGroupData.pNextWindow == PWINDOW) if (PWINDOW->m_sGroupData.pNextWindow == PWINDOW)
return; return;
if (isNumber(args, false)) {
// index starts from '1'; '0' means last window
const int INDEX = std::stoi(args);
if (INDEX > PWINDOW->getGroupSize())
return;
if (INDEX == 0)
PWINDOW->setGroupCurrent(PWINDOW->getGroupTail());
else
PWINDOW->setGroupCurrent(PWINDOW->getGroupWindowByIndex(INDEX - 1));
return;
}
if (args != "b" && args != "prev") { if (args != "b" && args != "prev") {
PWINDOW->setGroupCurrent(PWINDOW->m_sGroupData.pNextWindow); PWINDOW->setGroupCurrent(PWINDOW->m_sGroupData.pNextWindow);
} else { } else {
@@ -1204,7 +1225,7 @@ void CKeybindManager::alterSplitRatio(std::string args) {
} }
if (splitratio == 0) { if (splitratio == 0) {
if (args.find("exact") == 0) { if (args.starts_with("exact")) {
exact = true; exact = true;
splitratio = getPlusMinusKeywordResult(args.substr(5), 0); splitratio = getPlusMinusKeywordResult(args.substr(5), 0);
} else { } else {
@@ -1704,10 +1725,10 @@ void CKeybindManager::toggleOpaque(std::string unused) {
} }
void CKeybindManager::dpms(std::string arg) { void CKeybindManager::dpms(std::string arg) {
bool enable = arg.find("on") == 0; bool enable = arg.starts_with("on");
std::string port = ""; std::string port = "";
if (arg.find("toggle") == 0) if (arg.starts_with("toggle"))
enable = !std::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return !other->dpmsStatus; }); // enable if any is off enable = !std::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return !other->dpmsStatus; }); // enable if any is off
if (arg.find_first_of(' ') != std::string::npos) if (arg.find_first_of(' ') != std::string::npos)
@@ -1819,24 +1840,21 @@ void CKeybindManager::mouse(std::string args) {
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal(); const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords); CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(mouseCoords) && pWindow->m_sGroupData.pNextWindow) { if (pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(mouseCoords)) {
const wlr_box box = pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); for (auto& wd : pWindow->m_dWindowDecorations) {
if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) { if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
const int SIZE = pWindow->getGroupSize(); continue;
pWindow = pWindow->getGroupWindowByIndex((mouseCoords.x - box.x) * SIZE / box.width);
// hack if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); wd->onBeginWindowDragOnDeco(mouseCoords);
if (!pWindow->m_bIsFloating) { break;
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked;
g_pKeybindManager->m_bGroupsLocked = true;
g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow);
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
} }
} }
} }
if (!g_pInputManager->currentlyDraggedWindow)
g_pInputManager->currentlyDraggedWindow = pWindow; g_pInputManager->currentlyDraggedWindow = pWindow;
g_pInputManager->dragMode = MBIND_MOVE; g_pInputManager->dragMode = MBIND_MOVE;
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
} else { } else {
@@ -1946,12 +1964,9 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi
if (pWindow->m_sGroupData.deny) if (pWindow->m_sGroupData.deny)
return; return;
if (!pWindow->m_sGroupData.pNextWindow)
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property! g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property!
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("misc:group_insert_after_current")->intValue; static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail(); pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail();
pWindowInDirection->insertWindowToGroup(pWindow); pWindowInDirection->insertWindowToGroup(pWindow);
@@ -1960,11 +1975,13 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow);
g_pCompositor->focusWindow(pWindow); g_pCompositor->focusWindow(pWindow);
g_pCompositor->warpCursorTo(pWindow->middle()); g_pCompositor->warpCursorTo(pWindow->middle());
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
} }
void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir) { void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir) {
static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("group:focus_removed_window")->intValue;
static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("misc:group_focus_removed_window")->intValue;
const auto PWINDOWPREV = pWindow->getGroupPrevious(); const auto PWINDOWPREV = pWindow->getGroupPrevious();
eDirection direction; eDirection direction;
@@ -2003,7 +2020,10 @@ void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string&
void CKeybindManager::moveIntoGroup(std::string args) { void CKeybindManager::moveIntoGroup(std::string args) {
char arg = args[0]; char arg = args[0];
static auto* const BIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue; static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue;
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked)
return;
if (!isDirection(args)) { if (!isDirection(args)) {
Debug::log(ERR, "Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); Debug::log(ERR, "Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg);
@@ -2021,13 +2041,18 @@ void CKeybindManager::moveIntoGroup(std::string args) {
return; return;
// Do not move window into locked group if binds:ignore_group_lock is false // Do not move window into locked group if binds:ignore_group_lock is false
if (!*BIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->getGroupHead()->m_sGroupData.locked))) if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->getGroupHead()->m_sGroupData.locked)))
return; return;
moveWindowIntoGroup(PWINDOW, PWINDOWINDIR); moveWindowIntoGroup(PWINDOW, PWINDOWINDIR);
} }
void CKeybindManager::moveOutOfGroup(std::string args) { void CKeybindManager::moveOutOfGroup(std::string args) {
static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue;
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked)
return;
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow) if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow)
@@ -2049,6 +2074,12 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow; const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!PWINDOW || PWINDOW->m_bIsFullscreen) if (!PWINDOW || PWINDOW->m_bIsFullscreen)
return; return;
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
return;
}
const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg);
const bool ISWINDOWGROUP = PWINDOW->m_sGroupData.pNextWindow; const bool ISWINDOWGROUP = PWINDOW->m_sGroupData.pNextWindow;

View File

@@ -23,12 +23,14 @@ struct SKeybind {
bool mouse = false; bool mouse = false;
bool nonConsuming = false; bool nonConsuming = false;
bool transparent = false; bool transparent = false;
bool ignoreMods = false;
// DO NOT INITIALIZE // DO NOT INITIALIZE
bool shadowed = false; bool shadowed = false;
}; };
enum eFocusWindowMode { enum eFocusWindowMode
{
MODE_CLASS_REGEX = 0, MODE_CLASS_REGEX = 0,
MODE_TITLE_REGEX, MODE_TITLE_REGEX,
MODE_ADDRESS, MODE_ADDRESS,

View File

@@ -74,7 +74,7 @@ void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) {
g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID)->m_pLastFocusedWindow = pWindow; g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID)->m_pLastFocusedWindow = pWindow;
} }
void CHyprXWaylandManager::getGeometryForWindow(CWindow* pWindow, wlr_box* pbox) { void CHyprXWaylandManager::getGeometryForWindow(CWindow* pWindow, CBox* pbox) {
if (pWindow->m_bIsX11) { if (pWindow->m_bIsX11) {
const auto SIZEHINTS = pWindow->m_uSurface.xwayland->size_hints; const auto SIZEHINTS = pWindow->m_uSurface.xwayland->size_hints;
@@ -89,8 +89,10 @@ void CHyprXWaylandManager::getGeometryForWindow(CWindow* pWindow, wlr_box* pbox)
pbox->width = pWindow->m_uSurface.xwayland->width; pbox->width = pWindow->m_uSurface.xwayland->width;
pbox->height = pWindow->m_uSurface.xwayland->height; pbox->height = pWindow->m_uSurface.xwayland->height;
} }
} else } else {
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, pbox); wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, pbox->pWlr());
pbox->applyFromWlr();
}
} }
std::string CHyprXWaylandManager::getTitle(CWindow* pWindow) { std::string CHyprXWaylandManager::getTitle(CWindow* pWindow) {
@@ -160,11 +162,11 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f
windowPos = windowPos + PMONITOR->vecXWaylandPosition; // move to correct position for xwayland windowPos = windowPos + PMONITOR->vecXWaylandPosition; // move to correct position for xwayland
} }
if (!force && ((pWindow->m_vReportedSize == size && windowPos == pWindow->m_vReportedPosition) || (pWindow->m_vReportedSize == size && !pWindow->m_bIsX11))) if (!force && ((pWindow->m_vPendingReportedSize == size && windowPos == pWindow->m_vReportedPosition) || (pWindow->m_vPendingReportedSize == size && !pWindow->m_bIsX11)))
return; return;
pWindow->m_vReportedPosition = windowPos; pWindow->m_vReportedPosition = windowPos;
pWindow->m_vReportedSize = size; pWindow->m_vPendingReportedSize = size;
pWindow->m_fX11SurfaceScaledBy = 1.f; pWindow->m_fX11SurfaceScaledBy = 1.f;
@@ -178,12 +180,15 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f
if (pWindow->m_bIsX11) if (pWindow->m_bIsX11)
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, windowPos.x, windowPos.y, size.x, size.y); wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, windowPos.x, windowPos.y, size.x, size.y);
else else
wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x, size.y); pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x, size.y), size.floor()));
} }
void CHyprXWaylandManager::setWindowStyleTiled(CWindow* pWindow, uint32_t edgez) { void CHyprXWaylandManager::setWindowStyleTiled(CWindow* pWindow, uint32_t edgez) {
if (!pWindow->m_bIsX11) if (pWindow->m_bIsX11)
return;
wlr_xdg_toplevel_set_tiled(pWindow->m_uSurface.xdg->toplevel, edgez); wlr_xdg_toplevel_set_tiled(pWindow->m_uSurface.xdg->toplevel, edgez);
wlr_xdg_toplevel_set_maximized(pWindow->m_uSurface.xdg->toplevel, true);
} }
wlr_surface* CHyprXWaylandManager::surfaceAt(CWindow* pWindow, const Vector2D& client, Vector2D& surface) { wlr_surface* CHyprXWaylandManager::surfaceAt(CWindow* pWindow, const Vector2D& client, Vector2D& surface) {

View File

@@ -15,7 +15,7 @@ class CHyprXWaylandManager {
wlr_surface* getWindowSurface(CWindow*); wlr_surface* getWindowSurface(CWindow*);
void activateSurface(wlr_surface*, bool); void activateSurface(wlr_surface*, bool);
void activateWindow(CWindow*, bool); void activateWindow(CWindow*, bool);
void getGeometryForWindow(CWindow*, wlr_box*); void getGeometryForWindow(CWindow*, CBox*);
std::string getTitle(CWindow*); std::string getTitle(CWindow*);
std::string getAppIDClass(CWindow*); std::string getAppIDClass(CWindow*);
void sendCloseWindow(CWindow*); void sendCloseWindow(CWindow*);

View File

@@ -41,8 +41,6 @@ void CInputManager::simulateMouseMovement() {
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
m_vLastCursorPosFloored = m_vLastCursorPosFloored - Vector2D(1, 1); // hack: force the mouseMoveUnified to report without making this a refocus. m_vLastCursorPosFloored = m_vLastCursorPosFloored - Vector2D(1, 1); // hack: force the mouseMoveUnified to report without making this a refocus.
mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000); mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000);
m_tmrLastCursorMovement.reset();
} }
void CInputManager::sendMotionEventsToFocused() { void CInputManager::sendMotionEventsToFocused() {
@@ -67,15 +65,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto* const PMOUSEREFOCUS = &g_pConfigManager->getConfigValuePtr("input:mouse_refocus")->intValue; static auto* const PMOUSEREFOCUS = &g_pConfigManager->getConfigValuePtr("input:mouse_refocus")->intValue;
static auto* const PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue; static auto* const PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue;
static auto* const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue; static auto* const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
static auto* const PHOGFOCUS = &g_pConfigManager->getConfigValuePtr("misc:layers_hog_keyboard_focus")->intValue;
static auto* const PFLOATBEHAVIOR = &g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus")->intValue; static auto* const PFLOATBEHAVIOR = &g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus")->intValue;
static auto* const PMOUSEFOCUSMON = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_focuses_monitor")->intValue; static auto* const PMOUSEFOCUSMON = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_focuses_monitor")->intValue;
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue; static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
static auto* const PRESIZECURSORICON = &g_pConfigManager->getConfigValuePtr("general:hover_icon_on_border")->intValue; static auto* const PRESIZECURSORICON = &g_pConfigManager->getConfigValuePtr("general:hover_icon_on_border")->intValue;
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue; static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
const auto FOLLOWMOUSE = *PFOLLOWONDND && m_sDrag.drag ? 1 : *PFOLLOWMOUSE; const auto FOLLOWMOUSE = *PFOLLOWONDND && m_sDrag.drag ? 1 : *PFOLLOWMOUSE;
@@ -102,11 +96,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored && !refocus) if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored && !refocus)
return; return;
EMIT_HOOK_EVENT_CANCELLABLE("mouseMove", MOUSECOORDSFLOORED);
if (time) if (time)
g_pCompositor->notifyIdleActivity(); g_pCompositor->notifyIdleActivity();
EMIT_HOOK_EVENT("mouseMove", MOUSECOORDSFLOORED);
m_vLastCursorPosFloored = MOUSECOORDSFLOORED; m_vLastCursorPosFloored = MOUSECOORDSFLOORED;
const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
@@ -118,6 +112,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (*PZOOMFACTOR != 1.f) if (*PZOOMFACTOR != 1.f)
g_pHyprRenderer->damageMonitor(PMONITOR); g_pHyprRenderer->damageMonitor(PMONITOR);
if (!PMONITOR->solitaryClient && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0)
g_pCompositor->scheduleFrameForMonitor(PMONITOR); g_pCompositor->scheduleFrameForMonitor(PMONITOR);
CWindow* forcedFocus = m_pForcedFocus; CWindow* forcedFocus = m_pForcedFocus;
@@ -187,9 +182,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// update stuff // update stuff
updateDragIcon(); updateDragIcon();
if (!m_sDrag.drag && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus) { if (!m_sDrag.drag && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && m_pLastMouseSurface) {
if (m_bLastFocusOnLS) { if (m_bLastFocusOnLS) {
foundSurface = g_pCompositor->m_pLastFocus; foundSurface = m_pLastMouseSurface;
pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface); pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface);
if (pFoundLayerSurface) { if (pFoundLayerSurface) {
surfacePos = g_pCompositor->getLayerSurfaceFromSurface(foundSurface)->position; surfacePos = g_pCompositor->getLayerSurfaceFromSurface(foundSurface)->position;
@@ -201,10 +196,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
pFoundLayerSurface = nullptr; pFoundLayerSurface = nullptr;
} }
} else if (g_pCompositor->m_pLastWindow) { } else if (g_pCompositor->m_pLastWindow) {
foundSurface = g_pCompositor->m_pLastFocus; foundSurface = m_pLastMouseSurface;
pFoundWindow = g_pCompositor->m_pLastWindow; pFoundWindow = g_pCompositor->m_pLastWindow;
surfacePos = g_pCompositor->m_pLastWindow->m_vRealPosition.vec(); surfaceCoords = g_pCompositor->vectorToSurfaceLocal(mouseCoords, pFoundWindow, foundSurface);
m_bFocusHeldByButtons = true; m_bFocusHeldByButtons = true;
m_bRefocusHeldByButtons = refocus; m_bRefocusHeldByButtons = refocus;
@@ -306,19 +301,19 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (g_pHyprRenderer->m_bHasARenderedCursor) { if (g_pHyprRenderer->m_bHasARenderedCursor) {
// TODO: maybe wrap? // TODO: maybe wrap?
if (m_ecbClickBehavior == CLICKMODE_KILL) if (m_ecbClickBehavior == CLICKMODE_KILL)
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "crosshair"); setCursorImageOverride("crosshair");
else else
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "left_ptr"); setCursorImageOverride("left_ptr");
} }
m_bEmptyFocusCursorSet = true; m_bEmptyFocusCursorSet = true;
} }
wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat); wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat);
m_pLastMouseSurface = nullptr;
if (refocus) { // if we are forcing a refocus, and we don't find a surface, clear the kb focus too! if (refocus || !g_pCompositor->m_pLastWindow) // if we are forcing a refocus, and we don't find a surface, clear the kb focus too!
g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(nullptr);
}
return; return;
} }
@@ -340,13 +335,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
bool allowKeyboardRefocus = true; bool allowKeyboardRefocus = true;
if (*PHOGFOCUS && !refocus && g_pCompositor->m_pLastFocus) { if (!refocus && g_pCompositor->m_pLastFocus) {
const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus);
if (PLS && PLS->layerSurface->current.keyboard_interactive) { if (PLS && PLS->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
allowKeyboardRefocus = false; allowKeyboardRefocus = false;
} }
}
// set the values for use // set the values for use
if (refocus) { if (refocus) {
@@ -361,6 +355,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return; return;
} }
if (pFoundWindow && foundSurface == pFoundWindow->m_pWLSurface.wlr() && !m_bCursorImageOverridden) {
const auto BOX = pFoundWindow->getWindowMainSurfaceBox();
if (!VECINRECT(mouseCoords, BOX.x, BOX.y, BOX.x + BOX.width, BOX.y + BOX.height))
setCursorImageOverride("left_ptr");
else
restoreCursorIconToApp();
}
if (pFoundWindow) { if (pFoundWindow) {
// change cursor icon if hovering over border // change cursor icon if hovering over border
if (*PRESIZEONBORDER && *PRESIZECURSORICON) { if (*PRESIZEONBORDER && *PRESIZECURSORICON) {
@@ -371,35 +373,23 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
} }
} }
// if we're on an input deco, reset cursor. Don't on overridden
// if (!m_bCursorImageOverridden) {
// if (!VECINRECT(m_vLastCursorPosFloored, pFoundWindow->m_vRealPosition.vec().x, pFoundWindow->m_vRealPosition.vec().y,
// pFoundWindow->m_vRealPosition.vec().x + pFoundWindow->m_vRealSize.vec().x, pFoundWindow->m_vRealPosition.vec().y + pFoundWindow->m_vRealSize.vec().y)) {
// wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "left_ptr");
// cursorSurfaceInfo.bUsed = false;
// } else if (!cursorSurfaceInfo.bUsed) {
// cursorSurfaceInfo.bUsed = true;
// wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, cursorSurfaceInfo.pSurface, cursorSurfaceInfo.vHotspot.x, cursorSurfaceInfo.vHotspot.y);
// }
// }
if (FOLLOWMOUSE != 1 && !refocus) { if (FOLLOWMOUSE != 1 && !refocus) {
if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow && if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow &&
((pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR == 2) || (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR != 0))) { ((pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR == 2) || (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR != 0))) {
// enter if change floating style // enter if change floating style
if (FOLLOWMOUSE != 3 && allowKeyboardRefocus) if (FOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface); g_pCompositor->focusWindow(pFoundWindow, foundSurface);
m_pLastMouseSurface = foundSurface;
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} else if (FOLLOWMOUSE == 2 || FOLLOWMOUSE == 3) { } else if (FOLLOWMOUSE == 2 || FOLLOWMOUSE == 3) {
m_pLastMouseSurface = foundSurface;
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} }
if (pFoundWindow == g_pCompositor->m_pLastWindow) { if (pFoundWindow == g_pCompositor->m_pLastWindow) {
if (foundSurface != g_pCompositor->m_pLastFocus || m_bLastFocusOnLS) { m_pLastMouseSurface = foundSurface;
// ^^^ changed the subsurface ^^^ came back from a LS
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} }
}
if (FOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow) if (FOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow)
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
@@ -421,7 +411,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
} }
if (pFoundLayerSurface && if (pFoundLayerSurface &&
(pFoundLayerSurface->layerSurface->current.keyboard_interactive || (pFoundLayerSurface->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP && !g_pCompositor->m_pLastWindow)) && (pFoundLayerSurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE ||
(pFoundLayerSurface->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP && !g_pCompositor->m_pLastWindow)) &&
FOLLOWMOUSE != 3 && allowKeyboardRefocus) { FOLLOWMOUSE != 3 && allowKeyboardRefocus) {
g_pCompositor->focusSurface(foundSurface); g_pCompositor->focusSurface(foundSurface);
} }
@@ -430,14 +421,15 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
m_bLastFocusOnLS = true; m_bLastFocusOnLS = true;
} }
m_pLastMouseSurface = foundSurface;
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
} }
void CInputManager::onMouseButton(wlr_pointer_button_event* e) { void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
g_pCompositor->notifyIdleActivity(); EMIT_HOOK_EVENT_CANCELLABLE("mouseButton", e);
EMIT_HOOK_EVENT("mouseButton", e); g_pCompositor->notifyIdleActivity();
m_tmrLastCursorMovement.reset(); m_tmrLastCursorMovement.reset();
@@ -473,32 +465,72 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
else else
g_pHyprRenderer->m_bWindowRequestedCursorHide = false; g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
if (!cursorImageUnlocked() || !g_pHyprRenderer->shouldRenderCursor()) if (!cursorImageUnlocked() || !g_pHyprRenderer->m_bHasARenderedCursor)
return; return;
// cursorSurfaceInfo.pSurface = e->surface; if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
m_sCursorSurfaceInfo.wlSurface.unassign();
// if (e->surface) { if (e->surface) {
// hyprListener_CursorSurfaceDestroy.removeCallback(); m_sCursorSurfaceInfo.wlSurface.assign(e->surface);
// hyprListener_CursorSurfaceDestroy.initCallback( m_sCursorSurfaceInfo.vHotspot = {e->hotspot_x, e->hotspot_y};
// &e->surface->events.destroy, [&](void* owner, void* data) { cursorSurfaceInfo.pSurface = nullptr; }, this, "InputManager"); m_sCursorSurfaceInfo.hidden = false;
// cursorSurfaceInfo.vHotspot = {e->hotspot_x, e->hotspot_y}; } else {
// } m_sCursorSurfaceInfo.vHotspot = {};
m_sCursorSurfaceInfo.hidden = true;
}
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) m_sCursorSurfaceInfo.name = "";
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, e->surface, e->hotspot_x, e->hotspot_y);
m_sCursorSurfaceInfo.inUse = true;
g_pHyprRenderer->setCursorSurface(e->surface, e->hotspot_x, e->hotspot_y);
}
} }
void CInputManager::processMouseRequest(wlr_cursor_shape_manager_v1_request_set_shape_event* e) { void CInputManager::processMouseRequest(wlr_cursor_shape_manager_v1_request_set_shape_event* e) {
if (!g_pHyprRenderer->shouldRenderCursor() || !cursorImageUnlocked()) if (!g_pHyprRenderer->m_bHasARenderedCursor || !cursorImageUnlocked())
return; return;
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, wlr_cursor_shape_v1_name(e->shape)); m_sCursorSurfaceInfo.wlSurface.unassign();
m_sCursorSurfaceInfo.vHotspot = {};
m_sCursorSurfaceInfo.name = wlr_cursor_shape_v1_name(e->shape);
m_sCursorSurfaceInfo.hidden = false;
m_sCursorSurfaceInfo.inUse = true;
g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name);
}
}
void CInputManager::restoreCursorIconToApp() {
if (m_sCursorSurfaceInfo.inUse)
return;
if (m_sCursorSurfaceInfo.hidden) {
g_pHyprRenderer->setCursorSurface(nullptr, 0, 0);
return;
}
if (m_sCursorSurfaceInfo.name.empty()) {
if (m_sCursorSurfaceInfo.wlSurface.exists())
g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface.wlr(), m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y);
} else {
g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name);
}
m_sCursorSurfaceInfo.inUse = true;
}
void CInputManager::setCursorImageOverride(const std::string& name) {
if (m_bCursorImageOverridden)
return;
m_sCursorSurfaceInfo.inUse = false;
g_pHyprRenderer->setCursorFromName(name);
} }
bool CInputManager::cursorImageUnlocked() { bool CInputManager::cursorImageUnlocked() {
if (!g_pHyprRenderer->shouldRenderCursor()) if (!g_pHyprRenderer->m_bHasARenderedCursor)
return false; return false;
if (m_ecbClickBehavior == CLICKMODE_KILL) if (m_ecbClickBehavior == CLICKMODE_KILL)
@@ -519,7 +551,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
case CLICKMODE_DEFAULT: case CLICKMODE_DEFAULT:
Debug::log(LOG, "SetClickMode: DEFAULT"); Debug::log(LOG, "SetClickMode: DEFAULT");
m_ecbClickBehavior = CLICKMODE_DEFAULT; m_ecbClickBehavior = CLICKMODE_DEFAULT;
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "left_ptr"); g_pHyprRenderer->setCursorFromName("left_ptr");
break; break;
case CLICKMODE_KILL: case CLICKMODE_KILL:
@@ -531,7 +563,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
refocus(); refocus();
// set cursor // set cursor
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "crosshair"); g_pHyprRenderer->setCursorFromName("crosshair");
break; break;
default: break; default: break;
} }
@@ -551,25 +583,24 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal(); const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
const auto w = g_pCompositor->vectorToWindowIdeal(mouseCoords); const auto w = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (w && !w->m_bIsFullscreen && !w->hasPopupAt(mouseCoords) && w->m_sGroupData.pNextWindow) { if (w && !w->m_bIsFullscreen && !w->hasPopupAt(mouseCoords)) {
const wlr_box box = w->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); for (auto& wd : w->m_dWindowDecorations) {
if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) { if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
if (e->state == WLR_BUTTON_PRESSED) { continue;
const int SIZE = w->getGroupSize();
CWindow* pWindow = w->getGroupWindowByIndex((mouseCoords.x - box.x) * SIZE / box.width); if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) {
if (w != pWindow) wd->onMouseButtonOnDeco(mouseCoords, e);
w->setGroupCurrent(pWindow);
}
return; return;
} }
} }
}
// clicking on border triggers resize // clicking on border triggers resize
// TODO detect click on LS properly // TODO detect click on LS properly
if (*PRESIZEONBORDER && !m_bLastFocusOnLS) { if (*PRESIZEONBORDER && !m_bLastFocusOnLS) {
if (w && !w->m_bIsFullscreen) { if (w && !w->m_bIsFullscreen) {
const wlr_box real = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; const CBox real = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if ((!wlr_box_contains_point(&real, mouseCoords.x, mouseCoords.y) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) && !w->hasPopupAt(mouseCoords)) { if ((!real.containsPoint(mouseCoords) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) && !w->hasPopupAt(mouseCoords)) {
g_pKeybindManager->resizeWithBorder(e); g_pKeybindManager->resizeWithBorder(e);
return; return;
} }
@@ -581,7 +612,8 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
break; break;
if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) { if ((!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) /* No constraints */
&& (w && g_pCompositor->m_pLastWindow != w) /* window should change */) {
// a bit hacky // a bit hacky
// if we only pressed one button, allow us to refocus. m_lCurrentlyHeldButtons.size() > 0 will stick the focus // if we only pressed one button, allow us to refocus. m_lCurrentlyHeldButtons.size() > 0 will stick the focus
if (m_lCurrentlyHeldButtons.size() == 1) { if (m_lCurrentlyHeldButtons.size() == 1) {
@@ -631,7 +663,7 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) { void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
static auto* const PSCROLLFACTOR = &g_pConfigManager->getConfigValuePtr("input:touchpad:scroll_factor")->floatValue; static auto* const PSCROLLFACTOR = &g_pConfigManager->getConfigValuePtr("input:touchpad:scroll_factor")->floatValue;
static auto* const PGROUPBARSCROLLING = &g_pConfigManager->getConfigValuePtr("misc:groupbar_scrolling")->intValue; static auto* const PGROUPBARSCROLLING = &g_pConfigManager->getConfigValuePtr("group:groupbar:scrolling")->intValue;
auto factor = (*PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : *PSCROLLFACTOR); auto factor = (*PSCROLLFACTOR <= 0.f || e->source != WLR_AXIS_SOURCE_FINGER ? 1.f : *PSCROLLFACTOR);
@@ -643,8 +675,8 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
const auto pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS); const auto pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS);
if (*PGROUPBARSCROLLING && pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(MOUSECOORDS) && pWindow->m_sGroupData.pNextWindow) { if (*PGROUPBARSCROLLING && pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(MOUSECOORDS) && pWindow->m_sGroupData.pNextWindow) {
const wlr_box box = pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents(); const CBox box = g_pDecorationPositioner->getWindowDecorationBox(pWindow->getDecorationByType(DECORATION_GROUPBAR));
if (wlr_box_contains_point(&box, MOUSECOORDS.x, MOUSECOORDS.y)) { if (box.containsPoint(MOUSECOORDS)) {
if (e->delta > 0) if (e->delta > 0)
pWindow->setGroupCurrent(pWindow->m_sGroupData.pNextWindow); pWindow->setGroupCurrent(pWindow->m_sGroupData.pNextWindow);
else else
@@ -1011,7 +1043,7 @@ void CInputManager::setPointerConfigs() {
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE); libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
} else if (ACCELPROFILE == "flat") { } else if (ACCELPROFILE == "flat") {
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT); libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
} else if (ACCELPROFILE.find("custom") == 0) { } else if (ACCELPROFILE.starts_with("custom")) {
CVarList args = {ACCELPROFILE, 0, ' '}; CVarList args = {ACCELPROFILE, 0, ' '};
try { try {
double step = std::stod(args[1]); double step = std::stod(args[1]);
@@ -1175,7 +1207,7 @@ void CInputManager::updateDragIcon() {
switch (m_sDrag.dragIcon->drag->grab_type) { switch (m_sDrag.dragIcon->drag->grab_type) {
case WLR_DRAG_GRAB_KEYBOARD: break; case WLR_DRAG_GRAB_KEYBOARD: break;
case WLR_DRAG_GRAB_KEYBOARD_POINTER: { case WLR_DRAG_GRAB_KEYBOARD_POINTER: {
wlr_box box = {m_sDrag.pos.x - 2, m_sDrag.pos.y - 2, m_sDrag.dragIcon->surface->current.width + 4, m_sDrag.dragIcon->surface->current.height + 4}; CBox box = {m_sDrag.pos.x - 2, m_sDrag.pos.y - 2, m_sDrag.dragIcon->surface->current.width + 4, m_sDrag.dragIcon->surface->current.height + 4};
g_pHyprRenderer->damageBox(&box); g_pHyprRenderer->damageBox(&box);
m_sDrag.pos = getMouseCoordsInternal(); m_sDrag.pos = getMouseCoordsInternal();
break; break;
@@ -1202,12 +1234,22 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
return; return;
const auto MOUSECOORDS = getMouseCoordsInternal(); const auto MOUSECOORDS = getMouseCoordsInternal();
const auto PCONSTRAINT = constraintFromWlr(constraint);
pMouse->hyprListener_commitConstraint.removeCallback(); pMouse->hyprListener_commitConstraint.removeCallback();
if (pMouse->currentConstraint) { if (pMouse->currentConstraint)
if (constraint) { wlr_pointer_constraint_v1_send_deactivated(pMouse->currentConstraint);
const auto PCONSTRAINT = constraintFromWlr(constraint);
if (const auto PWINDOW = g_pCompositor->getWindowFromSurface(constraint->surface); PWINDOW) {
const auto RELATIVETO = PWINDOW->m_bIsX11 ?
(PWINDOW->m_bIsMapped ? PWINDOW->m_vRealPosition.goalv() :
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y})) :
PWINDOW->m_vRealPosition.goalv();
PCONSTRAINT->cursorPosOnActivate = (MOUSECOORDS - RELATIVETO) * PWINDOW->m_fX11SurfaceScaledBy;
}
if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) { if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) {
PCONSTRAINT->hintSet = true; PCONSTRAINT->hintSet = true;
PCONSTRAINT->positionHint = {constraint->current.cursor_hint.x, constraint->current.cursor_hint.y}; PCONSTRAINT->positionHint = {constraint->current.cursor_hint.x, constraint->current.cursor_hint.y};
@@ -1215,10 +1257,6 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT && constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED) if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT && constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
warpMouseToConstraintMiddle(PCONSTRAINT); warpMouseToConstraintMiddle(PCONSTRAINT);
}
wlr_pointer_constraint_v1_send_deactivated(pMouse->currentConstraint);
}
pMouse->currentConstraint = constraint; pMouse->currentConstraint = constraint;
pMouse->constraintActive = true; pMouse->constraintActive = true;
@@ -1231,7 +1269,7 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
// warp to the constraint // warp to the constraint
recheckConstraint(pMouse); recheckConstraint(pMouse);
constraintFromWlr(constraint)->active = true; PCONSTRAINT->active = true;
wlr_pointer_constraint_v1_send_activated(pMouse->currentConstraint); wlr_pointer_constraint_v1_send_activated(pMouse->currentConstraint);
@@ -1248,23 +1286,17 @@ void CInputManager::warpMouseToConstraintMiddle(SConstraint* pConstraint) {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(pConstraint->constraint->surface); const auto PWINDOW = g_pCompositor->getWindowFromSurface(pConstraint->constraint->surface);
if (PWINDOW) { if (PWINDOW) {
const auto RELATIVETO = PWINDOW->m_bIsX11 ? const auto RELATIVETO = pConstraint->getLogicConstraintPos();
(PWINDOW->m_bIsMapped ? PWINDOW->m_vRealPosition.goalv() :
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y})) :
PWINDOW->m_vRealPosition.goalv();
const auto HINTSCALE = PWINDOW->m_fX11SurfaceScaledBy; const auto HINTSCALE = PWINDOW->m_fX11SurfaceScaledBy;
if (pConstraint->hintSet) { auto HINT = pConstraint->hintSet ? pConstraint->positionHint : pConstraint->cursorPosOnActivate;
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, RELATIVETO.x + pConstraint->positionHint.x / HINTSCALE, RELATIVETO.y + pConstraint->positionHint.y / HINTSCALE);
wlr_seat_pointer_warp(pConstraint->constraint->seat, pConstraint->constraint->current.cursor_hint.x, pConstraint->constraint->current.cursor_hint.y);
} else {
const auto RELATIVESIZE = PWINDOW->m_bIsX11 ?
(PWINDOW->m_bIsMapped ? PWINDOW->m_vRealSize.goalv() :
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height})) :
PWINDOW->m_vRealSize.goalv();
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, RELATIVETO.x + RELATIVESIZE.x / 2.f, RELATIVETO.y + RELATIVESIZE.y / 2.f); if (HINT == Vector2D{-1, -1})
wlr_seat_pointer_warp(pConstraint->constraint->seat, RELATIVESIZE.x / 2.f, RELATIVESIZE.y / 2.f); HINT = pConstraint->getLogicConstraintSize() / 2.f;
if (HINT != Vector2D{-1, -1}) {
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, RELATIVETO.x + HINT.x / HINTSCALE, RELATIVETO.y + HINT.y / HINTSCALE);
wlr_seat_pointer_warp(pConstraint->constraint->seat, pConstraint->constraint->current.cursor_hint.x, pConstraint->constraint->current.cursor_hint.y);
} }
} }
} }
@@ -1439,6 +1471,12 @@ void CInputManager::setTabletConfigs() {
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output); wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output);
wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr); wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr);
} }
const auto REGION_POS = g_pConfigManager->getDeviceVec(t.name, "region_position", "input:tablet:region_position");
const auto REGION_SIZE = g_pConfigManager->getDeviceVec(t.name, "region_size", "input:tablet:region_size");
auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y};
if (!regionBox.empty())
wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr());
} }
} }
} }
@@ -1495,8 +1533,9 @@ void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
} }
void CInputManager::setCursorImageUntilUnset(std::string name) { void CInputManager::setCursorImageUntilUnset(std::string name) {
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, name.c_str()); g_pHyprRenderer->setCursorFromName(name.c_str());
m_bCursorImageOverridden = true; m_bCursorImageOverridden = true;
m_sCursorSurfaceInfo.inUse = false;
} }
void CInputManager::unsetCursorImage() { void CInputManager::unsetCursorImage() {
@@ -1504,8 +1543,7 @@ void CInputManager::unsetCursorImage() {
return; return;
m_bCursorImageOverridden = false; m_bCursorImageOverridden = false;
if (!g_pHyprRenderer->m_bWindowRequestedCursorHide) restoreCursorIconToApp();
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "left_ptr");
} }
std::string CInputManager::deviceNameToInternalString(std::string in) { std::string CInputManager::deviceNameToInternalString(std::string in) {
@@ -1583,14 +1621,33 @@ void CInputManager::setCursorIconOnBorder(CWindow* w) {
// give a small leeway (10 px) for corner icon // give a small leeway (10 px) for corner icon
const auto CORNER = *PROUNDING + BORDERSIZE + 10; const auto CORNER = *PROUNDING + BORDERSIZE + 10;
const auto mouseCoords = getMouseCoordsInternal(); const auto mouseCoords = getMouseCoordsInternal();
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; CBox box = w->getWindowMainSurfaceBox();
eBorderIconDirection direction = BORDERICON_NONE; eBorderIconDirection direction = BORDERICON_NONE;
wlr_box boxFullGrabInput = {box.x - *PEXTENDBORDERGRAB - BORDERSIZE, box.y - *PEXTENDBORDERGRAB - BORDERSIZE, box.width + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE), CBox boxFullGrabInput = {box.x - *PEXTENDBORDERGRAB - BORDERSIZE, box.y - *PEXTENDBORDERGRAB - BORDERSIZE, box.width + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE),
box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)}; box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)};
if (!wlr_box_contains_point(&boxFullGrabInput, mouseCoords.x, mouseCoords.y) || (!m_lCurrentlyHeldButtons.empty() && !currentlyDraggedWindow)) { if (w->hasPopupAt(mouseCoords))
direction = BORDERICON_NONE; direction = BORDERICON_NONE;
} else if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) { else if (!boxFullGrabInput.containsPoint(mouseCoords) || (!m_lCurrentlyHeldButtons.empty() && !currentlyDraggedWindow))
direction = BORDERICON_NONE;
else {
bool onDeco = false;
for (auto& wd : w->m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) {
onDeco = true;
break;
}
}
if (onDeco)
direction = BORDERICON_NONE;
else {
if (box.containsPoint(mouseCoords)) {
if (!w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) { if (!w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) {
direction = BORDERICON_NONE; direction = BORDERICON_NONE;
} else { } else {
@@ -1628,6 +1685,8 @@ void CInputManager::setCursorIconOnBorder(CWindow* w) {
direction = BORDERICON_RIGHT; direction = BORDERICON_RIGHT;
} }
} }
}
}
if (direction == m_eBorderIconDirection) if (direction == m_eBorderIconDirection)
return; return;

View File

@@ -115,6 +115,7 @@ class CInputManager {
// for dragging floating windows // for dragging floating windows
CWindow* currentlyDraggedWindow = nullptr; CWindow* currentlyDraggedWindow = nullptr;
eMouseBindMode dragMode = MBIND_INVALID; eMouseBindMode dragMode = MBIND_INVALID;
bool m_bWasDraggingWindow = false;
// for refocus to be forced // for refocus to be forced
CWindow* m_pForcedFocus = nullptr; CWindow* m_pForcedFocus = nullptr;
@@ -182,6 +183,7 @@ class CInputManager {
// for tracking mouse refocus // for tracking mouse refocus
CWindow* m_pLastMouseFocus = nullptr; CWindow* m_pLastMouseFocus = nullptr;
wlr_surface* m_pLastMouseSurface = nullptr;
private: private:
bool m_bCursorImageOverridden = false; bool m_bCursorImageOverridden = false;
@@ -225,15 +227,22 @@ class CInputManager {
void setBorderCursorIcon(eBorderIconDirection); void setBorderCursorIcon(eBorderIconDirection);
void setCursorIconOnBorder(CWindow* w); void setCursorIconOnBorder(CWindow* w);
// temporary. Obeys setUntilUnset.
void setCursorImageOverride(const std::string& name);
// cursor surface // cursor surface
// struct cursorSI { struct cursorSI {
// wlr_surface* pSurface = nullptr; bool hidden = false; // null surface = hidden
// Vector2D vHotspot; CWLSurface wlSurface;
// bool bUsed = false; Vector2D vHotspot;
// } cursorSurfaceInfo; std::string name; // if not empty, means set by name.
// DYNLISTENER(CursorSurfaceDestroy); bool inUse = false;
} m_sCursorSurfaceInfo;
void restoreCursorIconToApp(); // no-op if restored
friend class CKeybindManager; friend class CKeybindManager;
friend class CWLSurface;
}; };
inline std::unique_ptr<CInputManager> g_pInputManager; inline std::unique_ptr<CInputManager> g_pInputManager;

View File

@@ -3,7 +3,7 @@
#include "../../Compositor.hpp" #include "../../Compositor.hpp"
CInputMethodRelay::CInputMethodRelay() { CInputMethodRelay::CInputMethodRelay() {
g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, std::any param) { onKeyboardFocus(std::any_cast<wlr_surface*>(param)); }); g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast<wlr_surface*>(param)); });
} }
void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) { void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) {
@@ -178,7 +178,7 @@ void CInputMethodRelay::updateInputPopup(SIMEPopup* pPopup) {
bool cursorRect = PFOCUSEDTI->pWlrInput ? PFOCUSEDTI->pWlrInput->current.features & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE : true; bool cursorRect = PFOCUSEDTI->pWlrInput ? PFOCUSEDTI->pWlrInput->current.features & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE : true;
const auto PFOCUSEDSURFACE = focusedSurface(PFOCUSEDTI); const auto PFOCUSEDSURFACE = focusedSurface(PFOCUSEDTI);
auto cursorBox = PFOCUSEDTI->pWlrInput ? PFOCUSEDTI->pWlrInput->current.cursor_rectangle : PFOCUSEDTI->pV1Input->cursorRectangle; CBox cursorBox = PFOCUSEDTI->pWlrInput ? PFOCUSEDTI->pWlrInput->current.cursor_rectangle : PFOCUSEDTI->pV1Input->cursorRectangle;
CMonitor* pMonitor = nullptr; CMonitor* pMonitor = nullptr;
Vector2D parentPos; Vector2D parentPos;
@@ -209,7 +209,7 @@ void CInputMethodRelay::updateInputPopup(SIMEPopup* pPopup) {
if (!pMonitor) if (!pMonitor)
return; return;
wlr_box finalBox = cursorBox; CBox finalBox = cursorBox;
if (cursorBox.y + parentPos.y + pPopup->pSurface->surface->current.height + finalBox.height > pMonitor->vecPosition.y + pMonitor->vecSize.y) if (cursorBox.y + parentPos.y + pPopup->pSurface->surface->current.height + finalBox.height > pMonitor->vecPosition.y + pMonitor->vecSize.y)
finalBox.y -= pPopup->pSurface->surface->current.height + finalBox.height; finalBox.y -= pPopup->pSurface->surface->current.height + finalBox.height;
@@ -225,7 +225,7 @@ void CInputMethodRelay::updateInputPopup(SIMEPopup* pPopup) {
pPopup->lastSize = Vector2D(pPopup->pSurface->surface->current.width, pPopup->pSurface->surface->current.height); pPopup->lastSize = Vector2D(pPopup->pSurface->surface->current.width, pPopup->pSurface->surface->current.height);
wlr_input_popup_surface_v2_send_text_input_rectangle(pPopup->pSurface, &finalBox); wlr_input_popup_surface_v2_send_text_input_rectangle(pPopup->pSurface, finalBox.pWlr());
damagePopup(pPopup); damagePopup(pPopup);
} }

View File

@@ -51,7 +51,7 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
static auto* const PSWIPENUMBER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_numbered")->intValue; static auto* const PSWIPENUMBER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_numbered")->intValue;
static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue; static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.find("slidefadevert") == 0; m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
// commit // commit
std::string wsname = ""; std::string wsname = "";
@@ -200,7 +200,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue; static auto* const PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.find("slidefadevert") == 0; m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
m_sActiveSwipe.delta += VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx); m_sActiveSwipe.delta += VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx);

View File

@@ -244,8 +244,6 @@ void CInputManager::focusTablet(STablet* pTab, wlr_tablet_tool* pTool, bool moti
if (const auto PWINDOW = g_pCompositor->m_pLastWindow; PWINDOW) { if (const auto PWINDOW = g_pCompositor->m_pLastWindow; PWINDOW) {
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal(); const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
const auto LOCAL = CURSORPOS - PWINDOW->m_vRealPosition.goalv();
if (PTOOL->pSurface != g_pCompositor->m_pLastFocus) if (PTOOL->pSurface != g_pCompositor->m_pLastFocus)
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2); wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);
@@ -254,8 +252,14 @@ void CInputManager::focusTablet(STablet* pTab, wlr_tablet_tool* pTool, bool moti
wlr_tablet_v2_tablet_tool_notify_proximity_in(PTOOL->wlrTabletToolV2, pTab->wlrTabletV2, g_pCompositor->m_pLastFocus); wlr_tablet_v2_tablet_tool_notify_proximity_in(PTOOL->wlrTabletToolV2, pTab->wlrTabletV2, g_pCompositor->m_pLastFocus);
} }
if (motion) if (motion) {
wlr_tablet_v2_tablet_tool_notify_motion(PTOOL->wlrTabletToolV2, LOCAL.x, LOCAL.y); auto local = CURSORPOS - PWINDOW->m_vRealPosition.goalv();
if (PWINDOW->m_bIsX11)
local = local * PWINDOW->m_fX11SurfaceScaledBy;
wlr_tablet_v2_tablet_tool_notify_motion(PTOOL->wlrTabletToolV2, local.x, local.y);
}
} else { } else {
if (PTOOL->pSurface) if (PTOOL->pSurface)
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2); wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);

View File

@@ -32,12 +32,12 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
if (m_sTouchData.touchFocusWindow) { if (m_sTouchData.touchFocusWindow) {
if (m_sTouchData.touchFocusWindow->m_bIsX11) { if (m_sTouchData.touchFocusWindow->m_bIsX11) {
local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition.goalv(); local = (g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition.goalv()) * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy;
m_sTouchData.touchSurfaceOrigin = m_sTouchData.touchFocusWindow->m_vRealPosition.goalv();
} else { } else {
g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), m_sTouchData.touchFocusWindow, local); g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), m_sTouchData.touchFocusWindow, local);
}
m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local; m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local;
}
} else if (m_sTouchData.touchFocusLS) { } else if (m_sTouchData.touchFocusLS) {
local = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_sTouchData.touchFocusLS->geometry.x, m_sTouchData.touchFocusLS->geometry.y); local = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_sTouchData.touchFocusLS->geometry.x, m_sTouchData.touchFocusLS->geometry.y);
@@ -63,7 +63,9 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin; auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
if (m_sTouchData.touchFocusWindow->m_bIsX11)
local = local * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy;
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y); wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y);

View File

@@ -1,4 +1,4 @@
globber = run_command('find', '.', '-name', '*.cpp', check: true) globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
src = globber.stdout().strip().split('\n') src = globber.stdout().strip().split('\n')
executable('Hyprland', src, executable('Hyprland', src,

View File

@@ -9,6 +9,10 @@
#include <sstream> #include <sstream>
APICALL const char* __hyprland_api_get_hash() {
return GIT_COMMIT_HASH;
}
APICALL bool HyprlandAPI::registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn) { APICALL bool HyprlandAPI::registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
@@ -107,7 +111,7 @@ APICALL bool HyprlandAPI::removeFunctionHook(HANDLE handle, CFunctionHook* hook)
return g_pFunctionHookSystem->removeHook(hook); return g_pFunctionHookSystem->removeHook(hook);
} }
APICALL bool HyprlandAPI::addWindowDecoration(HANDLE handle, CWindow* pWindow, IHyprWindowDecoration* pDecoration) { APICALL bool HyprlandAPI::addWindowDecoration(HANDLE handle, CWindow* pWindow, std::unique_ptr<IHyprWindowDecoration> pDecoration) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
if (!PLUGIN) if (!PLUGIN)
@@ -116,11 +120,10 @@ APICALL bool HyprlandAPI::addWindowDecoration(HANDLE handle, CWindow* pWindow, I
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return false; return false;
PLUGIN->registeredDecorations.push_back(pDecoration); PLUGIN->registeredDecorations.push_back(pDecoration.get());
pWindow->m_dWindowDecorations.emplace_back(pDecoration); pWindow->addWindowDeco(std::move(pDecoration));
pWindow->updateWindowDecos();
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow);
return true; return true;
@@ -135,7 +138,7 @@ APICALL bool HyprlandAPI::removeWindowDecoration(HANDLE handle, IHyprWindowDecor
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
for (auto& d : w->m_dWindowDecorations) { for (auto& d : w->m_dWindowDecorations) {
if (d.get() == pDecoration) { if (d.get() == pDecoration) {
std::erase(w->m_dWindowDecorations, d); w->removeWindowDeco(pDecoration);
return true; return true;
} }
} }
@@ -153,13 +156,26 @@ APICALL bool HyprlandAPI::addConfigValue(HANDLE handle, const std::string& name,
if (!PLUGIN) if (!PLUGIN)
return false; return false;
if (name.find("plugin:") != 0) if (!name.starts_with("plugin:"))
return false; return false;
g_pConfigManager->addPluginConfigVar(handle, name, value); g_pConfigManager->addPluginConfigVar(handle, name, value);
return true; return true;
} }
APICALL bool HyprlandAPI::addConfigKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& key, const std::string& val)> fn) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
if (!g_pPluginSystem->m_bAllowConfigVars)
return false;
if (!PLUGIN)
return false;
g_pConfigManager->addPluginKeyword(handle, name, fn);
return true;
}
APICALL SConfigValue* HyprlandAPI::getConfigValue(HANDLE handle, const std::string& name) { APICALL SConfigValue* HyprlandAPI::getConfigValue(HANDLE handle, const std::string& name) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
@@ -301,7 +317,11 @@ APICALL std::vector<SFunctionMatch> HyprlandAPI::findFunctionsByName(HANDLE hand
count++; count++;
} }
return SYMBOLSDEMANGLED.substr(pos, SYMBOLSDEMANGLED.find('\n', pos + 1) - pos); // Skip the newline char itself
if (pos != 0)
pos++;
return SYMBOLSDEMANGLED.substr(pos, SYMBOLSDEMANGLED.find('\n', pos) - pos);
}; };
if (SYMBOLS.empty()) { if (SYMBOLS.empty()) {
@@ -334,3 +354,12 @@ APICALL std::vector<SFunctionMatch> HyprlandAPI::findFunctionsByName(HANDLE hand
return matches; return matches;
} }
APICALL SVersionInfo HyprlandAPI::getHyprlandVersion(HANDLE handle) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
if (!PLUGIN)
return {};
return {GIT_COMMIT_HASH, GIT_TAG, GIT_DIRTY != std::string(""), GIT_BRANCH, GIT_COMMIT_MESSAGE};
}

View File

@@ -23,12 +23,13 @@ Feel like the API is missing something you'd like to use in your plugin? Open an
#include "../helpers/Color.hpp" #include "../helpers/Color.hpp"
#include "HookSystem.hpp" #include "HookSystem.hpp"
#include "../SharedDefs.hpp" #include "../SharedDefs.hpp"
#include "../version.h"
#include <any> #include <any>
#include <functional> #include <functional>
#include <string> #include <string>
typedef std::function<void(void*, std::any)> HOOK_CALLBACK_FN; typedef std::function<void(void*, SCallbackInfo&, std::any)> HOOK_CALLBACK_FN;
typedef struct { typedef struct {
std::string name; std::string name;
std::string description; std::string description;
@@ -42,6 +43,14 @@ struct SFunctionMatch {
std::string demangled; std::string demangled;
}; };
struct SVersionInfo {
std::string hash;
std::string tag;
bool dirty = false;
std::string branch;
std::string message;
};
#define APICALL extern "C" #define APICALL extern "C"
#define EXPORT __attribute__((visibility("default"))) #define EXPORT __attribute__((visibility("default")))
#define REQUIRED #define REQUIRED
@@ -105,6 +114,14 @@ namespace HyprlandAPI {
*/ */
APICALL bool addConfigValue(HANDLE handle, const std::string& name, const SConfigValue& value); APICALL bool addConfigValue(HANDLE handle, const std::string& name, const SConfigValue& value);
/*
Add a config keyword.
This method may only be called in "pluginInit"
returns: true on success, false on fail
*/
APICALL bool addConfigKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& key, const std::string& val)> fn);
/* /*
Get a config value. Get a config value.
@@ -204,7 +221,7 @@ namespace HyprlandAPI {
returns: true on success. False otherwise. returns: true on success. False otherwise.
*/ */
APICALL bool addWindowDecoration(HANDLE handle, CWindow* pWindow, IHyprWindowDecoration* pDecoration); APICALL bool addWindowDecoration(HANDLE handle, CWindow* pWindow, std::unique_ptr<IHyprWindowDecoration> pDecoration);
/* /*
Removes a window decoration Removes a window decoration
@@ -250,4 +267,24 @@ namespace HyprlandAPI {
Empty means either none found or handle was invalid Empty means either none found or handle was invalid
*/ */
APICALL std::vector<SFunctionMatch> findFunctionsByName(HANDLE handle, const std::string& name); APICALL std::vector<SFunctionMatch> findFunctionsByName(HANDLE handle, const std::string& name);
/*
Returns the hyprland version data. It's highly advised to not run plugins compiled
for a different hash.
*/
APICALL SVersionInfo getHyprlandVersion(HANDLE handle);
}; };
/*
Get the hash this plugin/server was compiled with.
This function will end up in both hyprland and any/all plugins,
and can be found by a simple dlsym()
_get_hash() is server,
_get_client_hash() is client.
*/
APICALL EXPORT const char* __hyprland_api_get_hash();
APICALL inline EXPORT const char* __hyprland_api_get_client_hash() {
return GIT_COMMIT_HASH;
}

View File

@@ -78,6 +78,11 @@ void CFractionalScaleProtocolManager::getFractionalScale(wl_client* client, wl_r
const auto PSURFACE = wlr_surface_from_resource(surface); const auto PSURFACE = wlr_surface_from_resource(surface);
const auto PADDON = getAddonForSurface(PSURFACE); const auto PADDON = getAddonForSurface(PSURFACE);
if (PADDON->pResource) {
wl_resource_post_error(resource, WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale exists.");
return;
}
PADDON->pResource = wl_resource_create(client, &wp_fractional_scale_v1_interface, wl_resource_get_version(resource), id); PADDON->pResource = wl_resource_create(client, &wp_fractional_scale_v1_interface, wl_resource_get_version(resource), id);
wl_resource_set_implementation(PADDON->pResource, &fractionalScaleAddonImpl, PADDON, handleAddonDestroy); wl_resource_set_implementation(PADDON->pResource, &fractionalScaleAddonImpl, PADDON, handleAddonDestroy);

View File

@@ -119,7 +119,7 @@ CScreencopyClient::~CScreencopyClient() {
CScreencopyClient::CScreencopyClient() { CScreencopyClient::CScreencopyClient() {
lastMeasure.reset(); lastMeasure.reset();
lastFrame.reset(); lastFrame.reset();
tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, std::any data) { onTick(); }); tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, SCallbackInfo& info, std::any data) { onTick(); });
} }
void CScreencopyClient::onTick() { void CScreencopyClient::onTick() {
@@ -183,7 +183,7 @@ void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force
m_lFrames.remove(*frame); m_lFrames.remove(*frame);
} }
void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, wlr_box box) { void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, CBox box) {
const auto PCLIENT = clientFromResource(resource); const auto PCLIENT = clientFromResource(resource);
const auto PFRAME = &m_lFrames.emplace_back(); const auto PFRAME = &m_lFrames.emplace_back();
@@ -239,8 +239,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
} }
int ow, oh; int ow, oh;
wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh); wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh);
wlr_box_transform(&PFRAME->box, &PFRAME->box, PFRAME->pMonitor->transform, ow, oh); PFRAME->box.transform(PFRAME->pMonitor->transform, ow, oh).scale(PFRAME->pMonitor->scale).round();
scaleBox(&PFRAME->box, PFRAME->pMonitor->scale);
PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width; PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width;
@@ -263,20 +262,23 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
return; return;
} }
const auto PBUFFER = wlr_buffer_from_resource(buffer); const auto PBUFFER = wlr_buffer_try_from_resource(buffer);
if (!PBUFFER) { if (!PBUFFER) {
Debug::log(ERR, "[sc] invalid buffer in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
removeFrame(PFRAME); removeFrame(PFRAME);
return; return;
} }
if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) { if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) {
Debug::log(ERR, "[sc] invalid dimensions in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
removeFrame(PFRAME); removeFrame(PFRAME);
return; return;
} }
if (PFRAME->buffer) { if (PFRAME->buffer) {
Debug::log(ERR, "[sc] buffer used in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED, "frame already used"); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED, "frame already used");
removeFrame(PFRAME); removeFrame(PFRAME);
return; return;
@@ -290,6 +292,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF; PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF;
if (dmabufAttrs.format != PFRAME->dmabufFormat) { if (dmabufAttrs.format != PFRAME->dmabufFormat) {
Debug::log(ERR, "[sc] invalid buffer dma format in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
removeFrame(PFRAME); removeFrame(PFRAME);
return; return;
@@ -298,15 +301,18 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
wlr_buffer_end_data_ptr_access(PBUFFER); wlr_buffer_end_data_ptr_access(PBUFFER);
if (wlrBufferAccessFormat != PFRAME->shmFormat) { if (wlrBufferAccessFormat != PFRAME->shmFormat) {
Debug::log(ERR, "[sc] invalid buffer shm format in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
removeFrame(PFRAME); removeFrame(PFRAME);
return; return;
} else if ((int)wlrBufferAccessStride != PFRAME->shmStride) { } else if ((int)wlrBufferAccessStride != PFRAME->shmStride) {
Debug::log(ERR, "[sc] invalid buffer shm stride in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride"); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
removeFrame(PFRAME); removeFrame(PFRAME);
return; return;
} }
} else { } else {
Debug::log(ERR, "[sc] invalid buffer type in {:x}", (uintptr_t)PFRAME);
wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type"); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type");
removeFrame(PFRAME); removeFrame(PFRAME);
return; return;
@@ -325,7 +331,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
} }
void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) { void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) {
m_pLastMonitorBackBuffer = e->buffer; m_pLastMonitorBackBuffer = e->state->buffer;
shareAllFrames(pMonitor); shareAllFrames(pMonitor);
m_pLastMonitorBackBuffer = nullptr; m_pLastMonitorBackBuffer = nullptr;
} }
@@ -382,11 +388,13 @@ void CScreencopyProtocolManager::shareFrame(SScreencopyFrame* frame) {
uint32_t flags = 0; uint32_t flags = 0;
if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) { if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
if (!copyFrameDmabuf(frame)) { if (!copyFrameDmabuf(frame)) {
Debug::log(ERR, "[sc] dmabuf copy failed in {:x}", (uintptr_t)frame);
zwlr_screencopy_frame_v1_send_failed(frame->resource); zwlr_screencopy_frame_v1_send_failed(frame->resource);
return; return;
} }
} else { } else {
if (!copyFrameShm(frame, &now)) { if (!copyFrameShm(frame, &now)) {
Debug::log(ERR, "[sc] shm copy failed in {:x}", (uintptr_t)frame);
zwlr_screencopy_frame_v1_send_failed(frame->resource); zwlr_screencopy_frame_v1_send_failed(frame->resource);
return; return;
} }

View File

@@ -46,7 +46,7 @@ struct SScreencopyFrame {
uint32_t shmFormat = 0; uint32_t shmFormat = 0;
uint32_t dmabufFormat = 0; uint32_t dmabufFormat = 0;
wlr_box box = {0}; CBox box = {};
int shmStride = 0; int shmStride = 0;
bool overlayCursor = false; bool overlayCursor = false;
@@ -73,7 +73,7 @@ class CScreencopyProtocolManager {
void removeFrame(SScreencopyFrame* frame, bool force = false); void removeFrame(SScreencopyFrame* frame, bool force = false);
void displayDestroy(); void displayDestroy();
void captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, wlr_box box = {0, 0, 0, 0}); void captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, CBox box = {0, 0, 0, 0});
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer); void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer);

View File

@@ -200,7 +200,7 @@ void CTextInputV1ProtocolManager::handleSetContentType(wl_client* client, wl_res
void CTextInputV1ProtocolManager::handleSetCursorRectangle(wl_client* client, wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height) { void CTextInputV1ProtocolManager::handleSetCursorRectangle(wl_client* client, wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height) {
const auto PTI = tiFromResource(resource); const auto PTI = tiFromResource(resource);
PTI->cursorRectangle = wlr_box{x, y, width, height}; PTI->cursorRectangle = CBox{x, y, width, height};
} }
void CTextInputV1ProtocolManager::handleSetPreferredLanguage(wl_client* client, wl_resource* resource, const char* language) { void CTextInputV1ProtocolManager::handleSetPreferredLanguage(wl_client* client, wl_resource* resource, const char* language) {

View File

@@ -39,7 +39,7 @@ struct STextInputV1 {
uint32_t purpose = 0; uint32_t purpose = 0;
} pendingContentType; } pendingContentType;
wlr_box cursorRectangle = {0, 0, 0, 0}; CBox cursorRectangle = {0, 0, 0, 0};
bool operator==(const STextInputV1& other) { bool operator==(const STextInputV1& other) {
return other.client == client && other.resourceCaller == resourceCaller && other.resourceImpl == resourceImpl; return other.client == client && other.resourceCaller == resourceCaller && other.resourceImpl == resourceImpl;

View File

@@ -201,7 +201,7 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou
PFRAME->box = {0, 0, (int)(PFRAME->pWindow->m_vRealSize.vec().x * PMONITOR->scale), (int)(PFRAME->pWindow->m_vRealSize.vec().y * PMONITOR->scale)}; PFRAME->box = {0, 0, (int)(PFRAME->pWindow->m_vRealSize.vec().x * PMONITOR->scale), (int)(PFRAME->pWindow->m_vRealSize.vec().y * PMONITOR->scale)};
int ow, oh; int ow, oh;
wlr_output_effective_resolution(PMONITOR->output, &ow, &oh); wlr_output_effective_resolution(PMONITOR->output, &ow, &oh);
wlr_box_transform(&PFRAME->box, &PFRAME->box, PMONITOR->transform, ow, oh); PFRAME->box.transform(PMONITOR->transform, ow, oh).round();
PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width; PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width;
@@ -229,7 +229,7 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r
return; return;
} }
const auto PBUFFER = wlr_buffer_from_resource(buffer); const auto PBUFFER = wlr_buffer_try_from_resource(buffer);
if (!PBUFFER) { if (!PBUFFER) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
removeFrame(PFRAME); removeFrame(PFRAME);
@@ -301,9 +301,9 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp
if (PMONITOR != g_pCompositor->getMonitorFromID(f->pWindow->m_iMonitorID)) if (PMONITOR != g_pCompositor->getMonitorFromID(f->pWindow->m_iMonitorID))
continue; continue;
wlr_box geometry = {f->pWindow->m_vRealPosition.vec().x, f->pWindow->m_vRealPosition.vec().y, f->pWindow->m_vRealSize.vec().x, f->pWindow->m_vRealSize.vec().y}; CBox geometry = {f->pWindow->m_vRealPosition.vec().x, f->pWindow->m_vRealPosition.vec().y, f->pWindow->m_vRealSize.vec().x, f->pWindow->m_vRealSize.vec().y};
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry)) if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, geometry.pWlr()))
continue; continue;
shareFrame(f); shareFrame(f);
@@ -448,7 +448,7 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti
g_pHyprOpenGL->bindWlrOutputFb(); g_pHyprOpenGL->bindWlrOutputFb();
wlr_box monbox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; CBox monbox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 1.f); g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 1.f);
g_pHyprOpenGL->end(); g_pHyprOpenGL->end();

View File

@@ -58,9 +58,9 @@ void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver
} }
CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, std::any param) { this->updateAllOutputs(); }); g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); });
g_pHookSystem->hookDynamic("configReloaded", [this](void* self, std::any param) { this->updateAllOutputs(); }); g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); });
g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, std::any param) { g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) {
const auto PMONITOR = std::any_cast<CMonitor*>(param); const auto PMONITOR = std::any_cast<CMonitor*>(param);
std::erase_if(m_vXDGOutputs, [&](const auto& other) { std::erase_if(m_vXDGOutputs, [&](const auto& other) {
const auto REMOVE = other->monitor == PMONITOR; const auto REMOVE = other->monitor == PMONITOR;
@@ -74,14 +74,8 @@ CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver
void CXDGOutputProtocol::onManagerGetXDGOutput(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* outputResource) { void CXDGOutputProtocol::onManagerGetXDGOutput(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* outputResource) {
const auto OUTPUT = wlr_output_from_resource(outputResource); const auto OUTPUT = wlr_output_from_resource(outputResource);
if (!OUTPUT)
return;
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(OUTPUT); const auto PMONITOR = g_pCompositor->getMonitorFromOutput(OUTPUT);
if (!PMONITOR)
return;
SXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique<SXDGOutput>(PMONITOR)).get(); SXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique<SXDGOutput>(PMONITOR)).get();
#ifndef NO_XWAYLAND #ifndef NO_XWAYLAND
if (g_pXWaylandManager->m_sWLRXWayland && g_pXWaylandManager->m_sWLRXWayland->server && g_pXWaylandManager->m_sWLRXWayland->server->client == client) if (g_pXWaylandManager->m_sWLRXWayland && g_pXWaylandManager->m_sWLRXWayland->server && g_pXWaylandManager->m_sWLRXWayland->server->client == client)
@@ -99,6 +93,10 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(wl_client* client, wl_resource* r
pXDGOutput->resource->setImplementation(&OUTPUT_IMPL, nullptr); pXDGOutput->resource->setImplementation(&OUTPUT_IMPL, nullptr);
pXDGOutput->resource->setData(this); pXDGOutput->resource->setData(this);
if (!PMONITOR)
return;
const auto XDGVER = pXDGOutput->resource->version(); const auto XDGVER = pXDGOutput->resource->version();
if (XDGVER >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) if (XDGVER >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION)
@@ -116,7 +114,7 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(wl_client* client, wl_resource* r
void CXDGOutputProtocol::updateOutputDetails(SXDGOutput* pOutput) { void CXDGOutputProtocol::updateOutputDetails(SXDGOutput* pOutput) {
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue; static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
if (!pOutput->resource->good()) if (!pOutput->resource->good() || !pOutput->monitor)
return; return;
const auto POS = pOutput->isXWayland ? pOutput->monitor->vecXWaylandPosition : pOutput->monitor->vecPosition; const auto POS = pOutput->isXWayland ? pOutput->monitor->vecXWaylandPosition : pOutput->monitor->vecPosition;
@@ -133,6 +131,10 @@ void CXDGOutputProtocol::updateOutputDetails(SXDGOutput* pOutput) {
void CXDGOutputProtocol::updateAllOutputs() { void CXDGOutputProtocol::updateAllOutputs() {
for (auto& o : m_vXDGOutputs) { for (auto& o : m_vXDGOutputs) {
if (!o->monitor)
continue;
updateOutputDetails(o.get()); updateOutputDetails(o.get());
wlr_output_schedule_done(o->monitor->output); wlr_output_schedule_done(o->monitor->output);

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