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
cp ./LICENSE hyprland/
cp build/Hyprland hyprland/
cp hyprctl/hyprctl hyprland/
cp build/hyprctl/hyprctl hyprland/
cp subprojects/wlroots/build/libwlroots.so.12032 hyprland/
cp build/Hyprland hyprland/
cp -r example/ hyprland/
@@ -105,4 +105,4 @@ jobs:
- name: Configure
run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja
- name: Compile
run: make config && make release
run: make release

View File

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

2
.gitignore vendored
View File

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

108
CMakeLists.txt Normal file → Executable file
View File

@@ -21,37 +21,51 @@ message(STATUS "Gathering git info")
# Get git info
# hash and branch
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND git rev-parse HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND sh -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g'"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_MESSAGE
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND sh -c "git diff-index --quiet HEAD -- || echo \"dirty\""
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_DIRTY
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND sh -c "git describe --tags"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_TAG
OUTPUT_STRIP_TRAILING_WHITESPACE)
COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
#
#
# udis
add_subdirectory("subprojects/udis86")
# wlroots
message(STATUS "Setting up wlroots")
include(ExternalProject)
if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
if(BUILDTYPE_LOWER STREQUAL "release")
# Pass.
elseif(BUILDTYPE_LOWER STREQUAL "debug")
# Pass.
elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
set(BUILDTYPE_LOWER "debugoptimized")
elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
set(BUILDTYPE_LOWER "minsize")
elseif(BUILDTYPE_LOWER STREQUAL "none")
set(BUILDTYPE_LOWER "plain")
else()
set(BUILDTYPE_LOWER "release")
endif()
else()
set(BUILDTYPE_LOWER "release")
endif()
ExternalProject_Add(
wlroots
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
PATCH_COMMAND sed -E -i -e "s/(soversion = 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)
message(STATUS "Found WaylandScanner at ${WaylandScanner}")
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")
add_executable(Hyprland ${SRCFILES})
add_dependencies(Hyprland wlroots)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
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")
target_link_libraries(Hyprland asan)
add_compile_options(-fsanitize=address)
target_compile_options(Hyprland PUBLIC -fsanitize=address)
endif()
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)
endif()
check_include_file("execinfo.h" EXECINFOH)
if(EXECINFOH)
message(STATUS "Configuration supports execinfo")
add_compile_definitions(HAS_EXECINFO)
endif()
include(CheckLibraryExists)
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
if(HAVE_LIBEXECINFO)
@@ -147,24 +168,21 @@ if(NO_SYSTEMD)
message(STATUS "SYSTEMD support is disabled...")
else()
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined) checking deps...")
pkg_check_modules(LIBSYSTEMD libsystemd)
check_include_file("systemd/sd-daemon.h" SYSTEMDH)
if(LIBSYSTEMD_FOUND AND SYSTEMDH)
add_compile_definitions(USES_SYSTEMD)
target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}")
if(SYSTEMDH)
pkg_check_modules(LIBSYSTEMD libsystemd)
if (LIBSYSTEMD_FOUND)
add_compile_definitions(USES_SYSTEMD)
target_link_libraries(Hyprland "${LIBSYSTEMD_LIBRARIES}")
message(STATUS "Systemd found")
else()
message(WARNING "Systemd support requested but systemd libraries were not found")
endif()
else()
message(WARNING "Systemd support requested but libsystemd or systemd headers were not found")
message(WARNING "Systemd support requested but systemd headers were not found")
endif()
endif()
target_compile_definitions(Hyprland
PRIVATE
"GIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\""
"GIT_BRANCH=\"${GIT_BRANCH}\""
"GIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE}\""
"GIT_DIRTY=\"${GIT_DIRTY}\""
"GIT_TAG=\"${GIT_TAG}\"")
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
@@ -202,7 +220,7 @@ target_link_libraries(Hyprland
OpenGL::EGL
OpenGL::GL
Threads::Threads
${CMAKE_SOURCE_DIR}/subprojects/udis86/build/libudis86/liblibudis86.a
libudis86
)
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/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false)
protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
protocol("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false)
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
# hyprctl
add_subdirectory(hyprctl)

View File

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

View File

@@ -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
- Custom bezier curves for the best animations
- Powerful plugin support
- Tearing support for better gaming performance
- Easily expandable and readable codebase
- Fast and active development
- Not scared to provide bleeding-edge features

View File

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

View File

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

View File

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

View File

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

20
flake.lock generated
View File

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

View File

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

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

View File

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

View File

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

View File

@@ -1,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, 'staging/fractional-scale/fractional-scale-v1.xml'],
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
['wlr-foreign-toplevel-management-unstable-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['wlr-output-power-management-unstable-v1.xml'],

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();
}
void handleUserSignal(int sig) {
if (sig == SIGUSR1) {
// means we have to unwind a timed out event
throw std::exception();
}
}
CCompositor::CCompositor() {
m_iHyprlandPID = getpid();
@@ -74,6 +81,7 @@ CCompositor::CCompositor() {
CCompositor::~CCompositor() {
cleanup();
g_pDecorationPositioner.reset();
g_pPluginSystem.reset();
g_pHyprNotificationOverlay.reset();
g_pDebugOverlay.reset();
@@ -92,6 +100,7 @@ CCompositor::~CCompositor() {
g_pAnimationManager.reset();
g_pKeybindManager.reset();
g_pHookSystem.reset();
g_pWatchdog.reset();
}
void CCompositor::setRandomSplash() {
@@ -112,7 +121,7 @@ void CCompositor::initServer() {
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
signal(SIGSEGV, handleUnrecoverableSignal);
signal(SIGABRT, handleUnrecoverableSignal);
//wl_event_loop_add_signal(m_sWLEventLoop, SIGINT, handleCritSignal, nullptr);
signal(SIGUSR1, handleUserSignal);
initManagers(STAGE_PRIORITY);
@@ -124,6 +133,8 @@ void CCompositor::initServer() {
const auto LOGWLR = getenv("HYPRLAND_LOG_WLR");
if (LOGWLR && std::string(LOGWLR) == "1")
wlr_log_init(WLR_DEBUG, Debug::wlrLog);
else
wlr_log_init(WLR_ERROR, Debug::wlrLog);
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_sWLRIdle = wlr_idle_create(m_sWLDisplay);
m_sWLRIdleNotifier = wlr_idle_notifier_v1_create(m_sWLDisplay);
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_sWLRTearingControlMgr = wlr_tearing_control_manager_v1_create(m_sWLDisplay, 1);
if (!m_sWLRHeadlessBackend) {
Debug::log(CRIT, "Couldn't create the headless backend");
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_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_sWLRTearingControlMgr->events.new_object, &Events::listen_newTearingHint, m_sWLRTearingControlMgr, "TearingControlMgr");
if (m_sWRLDRMLeaseMgr)
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_pConfigManager->init();
g_pWatchdog = std::make_unique<CWatchdog>(); // requires config
} break;
case STAGE_LATE: {
Debug::log(LOG, "Creating the ThreadManager!");
@@ -428,6 +442,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the PluginSystem!");
g_pPluginSystem = std::make_unique<CPluginSystem>();
g_pConfigManager->handlePluginLoads();
Debug::log(LOG, "Creating the DecorationPositioner!");
g_pDecorationPositioner = std::make_unique<CDecorationPositioner>();
} break;
default: UNREACHABLE();
}
@@ -450,6 +467,25 @@ void CCompositor::removeLockFile() {
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() {
initAllSignals();
@@ -501,7 +537,9 @@ void CCompositor::startCompositor() {
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
if (sd_booted() > 0)
@@ -539,7 +577,7 @@ CMonitor* CCompositor::getMonitorFromName(const std::string& name) {
CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) {
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 nullptr;
@@ -597,38 +635,35 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceID) {
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};
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() &&
!w->m_bNoFocus)
auto box = w->getWindowMainSurfaceBox();
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint(pos) && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
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};
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden() &&
!w->m_bNoFocus)
auto box = w->getWindowMainSurfaceBox();
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint(pos) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
}
// pinned
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};
if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
auto box = w->getWindowMainSurfaceBox();
if (box.containsPoint(pos) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
// 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) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned &&
!w->m_bNoFocus)
auto box = w->getWindowMainSurfaceBox();
if (box.containsPoint(pos) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
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};
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)
auto box = w->getWindowMainSurfaceBox();
if (box.containsPoint(pos) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
@@ -640,15 +675,15 @@ CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows) {
wlr_box 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)
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint(pos) && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
}
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
@@ -666,16 +701,16 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows | std::views::reverse) {
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};
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() &&
!w->m_bX11ShouldntFocus && !w->m_bNoFocus)
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 && box.containsPoint(pos) && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() &&
!w->m_bX11ShouldntFocus && !w->m_bNoFocus)
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 && box.containsPoint(pos) && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_bNoFocus)
return w.get();
}
}
@@ -683,9 +718,9 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// pinned windows on top of floating regardless
for (auto& w : m_vWindows | std::views::reverse) {
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 (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y))
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
return w.get();
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.
for (auto& w : m_vWindows | std::views::reverse) {
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) {
// OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
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)) {
// Override Redirect
@@ -730,9 +765,9 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
}
}
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() &&
!w->m_bX11ShouldntFocus && !w->m_bNoFocus)
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 && box.containsPoint(pos) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_bNoFocus)
return w.get();
}
@@ -744,37 +779,36 @@ CWindow* CCompositor::windowFromCursor() {
if (PMONITOR->specialWorkspaceID) {
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};
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->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 && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) &&
!w->isHidden() && !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
wlr_box 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)
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && !w->m_bNoFocus)
return w.get();
}
}
// pinned
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};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && w->m_bPinned && !w->m_bNoFocus)
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
// 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) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bPinned &&
!w->m_bNoFocus)
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
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)
return w.get();
}
for (auto& w : m_vWindows) {
wlr_box 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)
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bNoFocus)
return w.get();
}
@@ -783,14 +817,14 @@ CWindow* CCompositor::windowFromCursor() {
CWindow* CCompositor::windowFloatingFromCursor() {
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};
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)
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
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();
}
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};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() &&
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
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)
return w.get();
}
@@ -810,8 +844,9 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
double subx, suby;
// calc for oversized windows... fucking bullshit, again.
wlr_box geom;
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
CBox 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);
@@ -830,6 +865,38 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
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) {
for (auto& m : m_vMonitors) {
if (m->output == out) {
@@ -842,6 +909,8 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
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) {
Debug::log(LOG, "Disallowing setting focus to a window due to there being an active input inhibitor layer.");
return;
@@ -850,6 +919,10 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
if (!pWindow || !windowValidMapped(pWindow)) {
if (!m_pLastWindow && !pWindow)
return;
const auto PLASTWINDOW = m_pLastWindow;
m_pLastWindow = nullptr;
@@ -961,6 +1034,9 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
} else {
std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1);
}
if (*PFOLLOWMOUSE == 0)
g_pInputManager->sendMotionEventsToFocused();
}
void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
@@ -1141,27 +1217,39 @@ void CCompositor::sanityCheckWorkspaces() {
auto it = m_vWorkspaces.begin();
while (it != m_vWorkspaces.end()) {
if ((*it)->m_bIndestructible)
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(it->get());
if (WORKSPACERULE.isPersistent) {
++it;
continue;
}
const auto WINDOWSONWORKSPACE = getWindowsOnWorkspace((*it)->m_iID);
const auto& WORKSPACE = *it;
const auto WINDOWSONWORKSPACE = getWindowsOnWorkspace(WORKSPACE->m_iID);
if ((WINDOWSONWORKSPACE == 0 && !isWorkspaceVisible((*it)->m_iID))) {
if (WINDOWSONWORKSPACE == 0) {
if (!isWorkspaceVisible(WORKSPACE->m_iID)) {
if ((*it)->m_bIsSpecialWorkspace) {
if ((*it)->m_fAlpha.fl() > 0.f /* don't abruptly end the fadeout */) {
++it;
continue;
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);
}
const auto PMONITOR = getMonitorFromID((*it)->m_iMonitorID);
if (PMONITOR && PMONITOR->specialWorkspaceID == (*it)->m_iID)
PMONITOR->setSpecialWorkspace(nullptr);
it = m_vWorkspaces.erase(it);
continue;
}
if (!WORKSPACE->m_bOnCreatedEmptyExecuted) {
if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd)
g_pKeybindManager->spawn(*cmd);
it = m_vWorkspaces.erase(it);
continue;
WORKSPACE->m_bOnCreatedEmptyExecuted = true;
}
}
++it;
@@ -1417,82 +1505,144 @@ void CCompositor::addToFadingOutSafe(CWindow* pWindow) {
CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
if (!isDirection(dir))
return nullptr;
// 0 -> history, 1 -> shared length
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);
const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y);
const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height);
if (!PMONITOR)
return nullptr; // ??
auto leaderValue = -1;
CWindow* leaderWindow = 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();
for (auto& w : m_vWindows) {
if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID))
continue;
const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y);
const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen)
continue;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
auto leaderValue = -1;
CWindow* leaderWindow = nullptr;
const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
if (!pWindow->m_bIsFloating) {
const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y);
const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height);
// for tiled windows, we calc edges
for (auto& w : m_vWindows) {
if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID))
continue;
double intersectLength = -1;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID)
continue;
switch (dir) {
case 'l':
if (STICKS(POSA.x, POSB.x + SIZEB.x)) {
intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
}
break;
case 'r':
if (STICKS(POSA.x + SIZEA.x, POSB.x)) {
intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
}
break;
case 't':
case 'u':
if (STICKS(POSA.y, POSB.y + SIZEB.y)) {
intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
}
break;
case 'b':
case 'd':
if (STICKS(POSA.y + SIZEA.y, POSB.y)) {
intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
}
break;
}
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen)
continue;
if (*PMETHOD == 0 /* history */) {
if (intersectLength > 0) {
const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
// get idx
int windowIDX = -1;
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) {
if (g_pCompositor->m_vWindowFocusHistory[i] == w.get()) {
windowIDX = i;
break;
const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y);
const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height);
double intersectLength = -1;
switch (dir) {
case 'l':
if (STICKS(POSA.x, POSB.x + SIZEB.x)) {
intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
}
break;
case 'r':
if (STICKS(POSA.x + SIZEA.x, POSB.x)) {
intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
}
break;
case 't':
case 'u':
if (STICKS(POSA.y, POSB.y + SIZEB.y)) {
intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
}
break;
case 'b':
case 'd':
if (STICKS(POSA.y + SIZEA.y, POSB.y)) {
intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
}
break;
}
if (*PMETHOD == 0 /* history */) {
if (intersectLength > 0) {
// get idx
int windowIDX = -1;
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) {
if (g_pCompositor->m_vWindowFocusHistory[i] == w.get()) {
windowIDX = i;
break;
}
}
windowIDX = g_pCompositor->m_vWindowFocusHistory.size() - windowIDX;
if (windowIDX > leaderValue) {
leaderValue = windowIDX;
leaderWindow = w.get();
}
}
windowIDX = g_pCompositor->m_vWindowFocusHistory.size() - windowIDX;
if (windowIDX > leaderValue) {
leaderValue = windowIDX;
} else /* length */ {
if (intersectLength > leaderValue) {
leaderValue = intersectLength;
leaderWindow = w.get();
}
}
} else /* length */ {
if (intersectLength > leaderValue) {
leaderValue = intersectLength;
}
} 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)
@@ -1567,7 +1717,7 @@ CWorkspace* CCompositor::getWorkspaceByName(const std::string& name) {
}
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));
}
@@ -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 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 GROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border_active")->data.get();
static auto* const GROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border")->data.get();
static auto* const GROUPACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border_locked_active")->data.get();
static auto* const GROUPINACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.group_border_locked")->data.get();
static auto* const GROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_active")->data.get();
static auto* const GROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_inactive")->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("group:col.border_locked_inactive")->data.get();
static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
static auto* const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue;
@@ -1774,8 +1924,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow
}
for (auto& d : pWindow->m_dWindowDecorations)
d->updateWindow(pWindow);
pWindow->updateWindowDecos();
}
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");
return nullptr;
}
} else if (name.find("desc:") == 0) {
} else if (name.starts_with("desc:")) {
const auto DESCRIPTION = name.substr(5);
for (auto& m : m_vMonitors) {
if (!m->output)
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();
}
}
@@ -2108,7 +2257,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(CWorkspace* pWorkspace) {
}
void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode mode) {
if (!windowValidMapped(pWindow))
if (!windowValidMapped(pWindow) || g_pCompositor->m_bUnsafeState)
return;
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 MODE = mode == FULLSCREEN_INVALID ? PWORKSPACE->m_efFullscreenMode : mode;
if (PWORKSPACE->m_bHasFullscreenWindow && on) {
Debug::log(LOG, "Rejecting fullscreen ON on a fullscreen workspace");
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();
updateWindowAnimatedDecorationValues(pWindow);
@@ -2193,15 +2344,30 @@ CWindow* CCompositor::getWindowByRegex(const std::string& regexp) {
std::regex regexCheck(regexp);
std::string matchCheck;
if (regexp.find("title:") == 0) {
if (regexp.starts_with("title:")) {
mode = MODE_TITLE_REGEX;
regexCheck = std::regex(regexp.substr(6));
} else if (regexp.find("address:") == 0) {
} else if (regexp.starts_with("address:")) {
mode = MODE_ADDRESS;
matchCheck = regexp.substr(8);
} else if (regexp.find("pid:") == 0) {
} else if (regexp.starts_with("pid:")) {
mode = MODE_PID;
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) {
@@ -2445,7 +2611,13 @@ int CCompositor::getNewSpecialID() {
}
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) {
@@ -2510,12 +2682,10 @@ CWindow* CCompositor::getForceFocus() {
}
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);
}
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);
}
void CCompositor::arrangeMonitors() {
@@ -2576,3 +2746,50 @@ void CCompositor::arrangeMonitors() {
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 "hyprerror/HyprError.hpp"
#include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp"
enum eManagersInitStage {
enum eManagersInitStage
{
STAGE_PRIORITY = 0,
STAGE_LATE
};
@@ -52,7 +54,6 @@ class CCompositor {
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_xdg_activation_v1* m_sWLRXDGActivation;
wlr_output_layout* m_sWLROutputLayout;
wlr_idle* m_sWLRIdle;
wlr_idle_notifier_v1* m_sWLRIdleNotifier;
wlr_layer_shell_v1* m_sWLRLayerShell;
wlr_xdg_shell* m_sWLRXDGShell;
@@ -84,6 +85,7 @@ class CCompositor {
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr;
wlr_tearing_control_manager_v1* m_sWLRTearingControlMgr;
// ------------------------------------------------- //
std::string m_szWLDisplaySocket = "";
@@ -118,7 +120,9 @@ class CCompositor {
bool m_bReadyToProcess = false;
bool m_bSessionActive = true;
bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; // because wlroots
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bIsShuttingDown = false;
// ------------------------------------------------- //
@@ -138,6 +142,7 @@ class CCompositor {
CWindow* vectorToWindowTiled(const Vector2D&);
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
CWindow* windowFromCursor();
CWindow* windowFloatingFromCursor();
CMonitor* getMonitorFromOutput(wlr_output*);
@@ -200,6 +205,10 @@ class CCompositor {
void notifyIdleActivity();
void setIdleActivityInhibit(bool inhibit);
void arrangeMonitors();
void enterUnsafeState();
void leaveUnsafeState();
void setPreferredScaleForSurface(wlr_surface* pSurface, double scale);
void setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform);
std::string explicitConfigPath;
@@ -207,6 +216,7 @@ class CCompositor {
void initAllSignals();
void setRandomSplash();
void initManagers(eManagersInitStage stage);
void prepareFallbackOutput();
uint64_t m_iHyprlandPID = 0;
};

View File

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

View File

@@ -13,7 +13,7 @@ CWindow::CWindow() {
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
m_dWindowDecorations.emplace_back(std::make_unique<CHyprDropShadowDecoration>(this)); // put the shadow so it's the first deco (has to be rendered first)
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
}
CWindow::~CWindow() {
@@ -37,30 +37,27 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
for (auto& wd : m_dWindowDecorations) {
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this);
const auto EXTENTS = wd->getWindowDecorationExtents();
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
}
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
if (m_pWLSurface.exists() && !m_bIsX11) {
wlr_box surfaceExtents = {0, 0, 0, 0};
CBox surfaceExtents = {0, 0, 0, 0};
// TODO: this could be better, perhaps make a getFullWindowRegion?
wlr_xdg_surface_for_each_popup_surface(
m_uSurface.xdg,
[](wlr_surface* surf, int sx, int sy, void* data) {
wlr_box* pSurfaceExtents = (wlr_box*)data;
CBox* pSurfaceExtents = (CBox*)data;
if (sx < pSurfaceExtents->x)
pSurfaceExtents->x = sx;
if (sy < pSurfaceExtents->y)
@@ -88,21 +85,21 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
return maxExtents;
}
wlr_box CWindow::getFullWindowBoundingBox() {
CBox CWindow::getFullWindowBoundingBox() {
if (m_sAdditionalConfigData.dimAround) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
}
auto maxExtents = getFullWindowExtents();
auto maxExtents = getFullWindowExtents();
wlr_box finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox;
}
wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
@@ -113,7 +110,7 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
POS = PMONITOR->vecPosition;
SIZE = PMONITOR->vecSize;
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
}
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
@@ -131,10 +128,10 @@ wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
SIZE.y += PMONITOR->vecReservedBottomRight.y;
}
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
}
wlr_box CWindow::getWindowInputBox() {
CBox CWindow::getWindowInputBox() {
const int BORDERSIZE = getRealBorderSize();
if (m_sAdditionalConfigData.dimAround) {
@@ -144,58 +141,45 @@ wlr_box CWindow::getWindowInputBox() {
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
for (auto& wd : m_dWindowDecorations) {
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
if (!wd->allowsInput())
continue;
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
const auto EXTENTS = wd->getWindowDecorationExtents();
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
}
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
// Add extents to the real base BB and return
wlr_box finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox;
}
CBox CWindow::getWindowMainSurfaceBox() {
return {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
}
SWindowDecorationExtents CWindow::getFullWindowReservedArea() {
SWindowDecorationExtents extents;
for (auto& wd : m_dWindowDecorations) {
const auto RESERVED = wd->getWindowDecorationReservedArea();
if (RESERVED.bottomRight == Vector2D{} && RESERVED.topLeft == Vector2D{})
continue;
extents.topLeft = extents.topLeft + RESERVED.topLeft;
extents.bottomRight = extents.bottomRight + RESERVED.bottomRight;
}
return extents;
return g_pDecorationPositioner->getWindowDecorationReserved(this);
}
void CWindow::updateWindowDecos() {
for (auto& wd : m_dWindowDecorations)
wd->updateWindow(this);
bool recalc = false;
if (!m_bIsMapped || isHidden())
return;
for (auto& wd : m_vDecosToRemove) {
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
if (it->get() == wd) {
g_pDecorationPositioner->uncacheDecoration(it->get());
it = m_dWindowDecorations.erase(it);
recalc = true;
if (it == m_dWindowDecorations.end())
@@ -204,10 +188,26 @@ void CWindow::updateWindowDecos() {
}
}
g_pDecorationPositioner->onWindowUpdate(this);
if (recalc)
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
m_vDecosToRemove.clear();
for (auto& wd : m_dWindowDecorations) {
wd->updateWindow(this);
}
}
void CWindow::addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco) {
m_dWindowDecorations.emplace_back(std::move(deco));
updateWindowDecos();
}
void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
m_vDecosToRemove.push_back(deco);
updateWindowDecos();
}
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);
} else {
if (!m_bIsMapped || !m_bMappedX11)
return -1;
PID = m_uSurface.xwayland->pid;
}
@@ -325,7 +328,8 @@ void CWindow::updateSurfaceOutputs() {
m_pWLSurface.wlr(),
[](wlr_surface* surf, int x, int y, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
},
this);
}
@@ -334,6 +338,10 @@ void CWindow::moveToWorkspace(int workspaceID) {
if (m_iWorkspaceID == workspaceID)
return;
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
const int OLDWORKSPACE = m_iWorkspaceID;
m_iWorkspaceID = workspaceID;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
@@ -352,6 +360,15 @@ void CWindow::moveToWorkspace(int workspaceID) {
// update xwayland coords
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec());
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) {
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE);
if (PWS) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWS->m_iMonitorID); PMONITOR)
PMONITOR->setSpecialWorkspace(nullptr);
}
}
}
CWindow* CWindow::X11TransientFor() {
@@ -414,11 +431,17 @@ void CWindow::onUnmap() {
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
PMONITOR->setSpecialWorkspace(nullptr);
}
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient == this)
PMONITOR->solitaryClient = nullptr;
}
void CWindow::onMap() {
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this));
m_pWLSurface.m_pOwner = this;
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
m_vRealPosition.resetAllCallbacks();
@@ -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,
"CWindow");
m_vReportedSize = m_vPendingReportedSize;
}
void CWindow::onBorderAngleAnimEnd(void* ptr) {
@@ -492,15 +517,19 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} else if (r.szRule == "opaque") {
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule.find("rounding") == 0) {
} else if (r.szRule == "immediate") {
m_sAdditionalConfigData.forceTearing = true;
} else if (r.szRule == "nearestneighbor") {
m_sAdditionalConfigData.nearestNeighbor = true;
} else if (r.szRule.starts_with("rounding")) {
try {
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.find("bordersize") == 0) {
} else if (r.szRule.starts_with("bordersize")) {
try {
m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.find("opacity") == 0) {
} else if (r.szRule.starts_with("opacity")) {
try {
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()); }
} else if (r.szRule == "noanim") {
m_sAdditionalConfigData.forceNoAnims = true;
} else if (r.szRule.find("animation") == 0) {
} else if (r.szRule.starts_with("animation")) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sAdditionalConfigData.animationStyle = STYLE;
} else if (r.szRule.find("bordercolor") == 0) {
} else if (r.szRule.starts_with("bordercolor")) {
try {
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
@@ -552,7 +581,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
m_sAdditionalConfigData.dimAround = true;
} else if (r.szRule == "keepaspectratio") {
m_sAdditionalConfigData.keepAspectRatio = true;
} else if (r.szRule.find("xray") == 0) {
} else if (r.szRule.starts_with("xray")) {
CVarList vars(r.szRule, 0, ' ');
try {
@@ -580,6 +609,8 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.borderSize = -1;
m_sAdditionalConfigData.keepAspectRatio = false;
m_sAdditionalConfigData.xray = -1;
m_sAdditionalConfigData.forceTearing = false;
m_sAdditionalConfigData.nearestNeighbor = false;
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
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) {
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;
}
@@ -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);
return;
}
if (!m_sGroupData.pNextWindow) {
m_sGroupData.pNextWindow = this;
m_sGroupData.head = true;
m_sGroupData.locked = false;
m_sGroupData.deny = false;
m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(this));
updateWindowDecos();
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(this));
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -735,6 +766,15 @@ int CWindow::getGroupSize() {
return size;
}
bool CWindow::canBeGroupedInto(CWindow* pWindow) {
return !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
&& ((m_eGroupRules & GROUP_INVADE && m_bFirstMap) // window ignore local group locks, or
|| (!pWindow->getGroupHead()->m_sGroupData.locked // target unlocked
&& !(m_sGroupData.pNextWindow && getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group
&& !m_sGroupData.deny // source is not denied entry
&& !(m_eGroupRules & GROUP_BARRED && m_bFirstMap); // group rule doesn't prevent adding window
}
CWindow* CWindow::getGroupWindowByIndex(int index) {
const int SIZE = getGroupSize();
index = ((index % SIZE) + SIZE) % SIZE;
@@ -791,6 +831,8 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode);
g_pHyprRenderer->damageWindow(pWindow);
pWindow->updateWindowDecos();
}
void CWindow::insertWindowToGroup(CWindow* pWindow) {
@@ -798,7 +840,7 @@ void CWindow::insertWindowToGroup(CWindow* pWindow) {
const auto ENDAT = m_sGroupData.pNextWindow;
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) {
BEGINAT->m_sGroupData.pNextWindow = pWindow;
@@ -874,6 +916,9 @@ bool CWindow::opaque() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall)
return false;
if (PWORKSPACE->m_fAlpha.fl() != 1.f)
return false;
@@ -925,3 +970,7 @@ int CWindow::getRealBorderSize() {
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
}
bool CWindow::canBeTorn() {
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
}

View File

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

View File

@@ -2,6 +2,7 @@
#include "../managers/KeybindManager.hpp"
#include <string.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -15,14 +16,20 @@
extern "C" char** environ;
CConfigManager::CConfigManager() {
configValues["general:col.active_border"].data = std::make_shared<CGradientValueData>(0xffffffff);
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_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["general:col.group_border_locked"].data = std::make_shared<CGradientValueData>(0x66775500);
configValues["general:col.group_border_locked_active"].data = std::make_shared<CGradientValueData>(0x66ff5500);
configValues["general:col.active_border"].data = std::make_shared<CGradientValueData>(0xffffffff);
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_active"].data = std::make_shared<CGradientValueData>(0xffff00ff);
configValues["group:col.border_active"].data = std::make_shared<CGradientValueData>(0x66ffff00);
configValues["group:col.border_inactive"].data = std::make_shared<CGradientValueData>(0x66777700);
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();
setDefaultAnimationVars();
@@ -76,10 +83,6 @@ void CConfigManager::setDefaultVars() {
((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_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:no_cursor_warps"].intValue = 0;
configValues["general:no_focus_fallback"].intValue = 0;
@@ -87,41 +90,56 @@ void CConfigManager::setDefaultVars() {
configValues["general:extend_border_grab_area"].intValue = 15;
configValues["general:hover_icon_on_border"].intValue = 1;
configValues["general:layout"].strValue = "dwindle";
configValues["general:allow_tearing"].intValue = 0;
configValues["misc:disable_hyprland_logo"].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:vfr"].intValue = 1;
configValues["misc:vrr"].intValue = 0;
configValues["misc:mouse_move_enables_dpms"].intValue = 0;
configValues["misc:key_press_enables_dpms"].intValue = 0;
configValues["misc:always_follow_on_dnd"].intValue = 1;
configValues["misc:layers_hog_keyboard_focus"].intValue = 1;
configValues["misc:animate_manual_resizes"].intValue = 0;
configValues["misc:animate_mouse_windowdragging"].intValue = 0;
configValues["misc:disable_autoreload"].intValue = 0;
configValues["misc:enable_swallow"].intValue = 0;
configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
configValues["misc:swallow_exception_regex"].strValue = STRVAL_EMPTY;
configValues["misc:focus_on_activate"].intValue = 0;
configValues["misc:no_direct_scanout"].intValue = 1;
configValues["misc:hide_cursor_on_touch"].intValue = 1;
configValues["misc:mouse_move_focuses_monitor"].intValue = 1;
configValues["misc:render_ahead_of_time"].intValue = 0;
configValues["misc:render_ahead_safezone"].intValue = 1;
configValues["misc:cursor_zoom_factor"].floatValue = 1.f;
configValues["misc:cursor_zoom_rigid"].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:groupbar_text_color"].intValue = 0xffffffff;
configValues["misc:background_color"].intValue = 0xff111111;
configValues["misc:disable_hyprland_logo"].intValue = 0;
configValues["misc:disable_splash_rendering"].intValue = 0;
configValues["misc:force_hypr_chan"].intValue = 0;
configValues["misc:force_default_wallpaper"].intValue = -1;
configValues["misc:vfr"].intValue = 1;
configValues["misc:vrr"].intValue = 0;
configValues["misc:mouse_move_enables_dpms"].intValue = 0;
configValues["misc:key_press_enables_dpms"].intValue = 0;
configValues["misc:always_follow_on_dnd"].intValue = 1;
configValues["misc:layers_hog_keyboard_focus"].intValue = 1;
configValues["misc:animate_manual_resizes"].intValue = 0;
configValues["misc:animate_mouse_windowdragging"].intValue = 0;
configValues["misc:disable_autoreload"].intValue = 0;
configValues["misc:enable_swallow"].intValue = 0;
configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
configValues["misc:swallow_exception_regex"].strValue = STRVAL_EMPTY;
configValues["misc:focus_on_activate"].intValue = 0;
configValues["misc:no_direct_scanout"].intValue = 1;
configValues["misc:hide_cursor_on_touch"].intValue = 1;
configValues["misc:mouse_move_focuses_monitor"].intValue = 1;
configValues["misc:render_ahead_of_time"].intValue = 0;
configValues["misc:render_ahead_safezone"].intValue = 1;
configValues["misc:cursor_zoom_factor"].floatValue = 1.f;
configValues["misc:cursor_zoom_rigid"].intValue = 0;
configValues["misc:allow_session_lock_restore"].intValue = 0;
configValues["misc:close_special_on_empty"].intValue = 1;
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:log_damage"].intValue = 0;
@@ -133,36 +151,38 @@ void CConfigManager::setDefaultVars() {
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
configValues["debug:manual_crash"].intValue = 0;
configValues["debug:suppress_errors"].intValue = 0;
configValues["debug:watchdog_timeout"].intValue = 5;
configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur:enabled"].intValue = 1;
configValues["decoration:blur:size"].intValue = 8;
configValues["decoration:blur:passes"].intValue = 1;
configValues["decoration:blur:ignore_opacity"].intValue = 0;
configValues["decoration:blur:new_optimizations"].intValue = 1;
configValues["decoration:blur:xray"].intValue = 0;
configValues["decoration:blur:noise"].floatValue = 0.0117;
configValues["decoration:blur:contrast"].floatValue = 0.8916;
configValues["decoration:blur:brightness"].floatValue = 0.8172;
configValues["decoration:blur:special"].intValue = 0;
configValues["decoration:active_opacity"].floatValue = 1;
configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 1;
configValues["decoration:multisample_edges"].intValue = 1;
configValues["decoration:no_blur_on_oversized"].intValue = 0;
configValues["decoration:drop_shadow"].intValue = 1;
configValues["decoration:shadow_range"].intValue = 4;
configValues["decoration:shadow_render_power"].intValue = 3;
configValues["decoration:shadow_ignore_window"].intValue = 1;
configValues["decoration:shadow_offset"].vecValue = Vector2D();
configValues["decoration:shadow_scale"].floatValue = 1.f;
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
configValues["decoration:dim_inactive"].intValue = 0;
configValues["decoration:dim_strength"].floatValue = 0.5f;
configValues["decoration:dim_special"].floatValue = 0.2f;
configValues["decoration:dim_around"].floatValue = 0.4f;
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur:enabled"].intValue = 1;
configValues["decoration:blur:size"].intValue = 8;
configValues["decoration:blur:passes"].intValue = 1;
configValues["decoration:blur:ignore_opacity"].intValue = 0;
configValues["decoration:blur:new_optimizations"].intValue = 1;
configValues["decoration:blur:xray"].intValue = 0;
configValues["decoration:blur:contrast"].floatValue = 0.8916;
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:active_opacity"].floatValue = 1;
configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 1;
configValues["decoration:no_blur_on_oversized"].intValue = 0;
configValues["decoration:drop_shadow"].intValue = 1;
configValues["decoration:shadow_range"].intValue = 4;
configValues["decoration:shadow_render_power"].intValue = 3;
configValues["decoration:shadow_ignore_window"].intValue = 1;
configValues["decoration:shadow_offset"].vecValue = Vector2D();
configValues["decoration:shadow_scale"].floatValue = 1.f;
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
configValues["decoration:dim_inactive"].intValue = 0;
configValues["decoration:dim_strength"].floatValue = 0.5f;
configValues["decoration:dim_special"].floatValue = 0.2f;
configValues["decoration:dim_around"].floatValue = 0.4f;
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:force_split"].intValue = 0;
@@ -186,6 +206,7 @@ void CConfigManager::setDefaultVars() {
configValues["master:inherit_fullscreen"].intValue = 1;
configValues["master:allow_small_split"].intValue = 0;
configValues["master:smart_resizing"].intValue = 1;
configValues["master:drop_at_cursor"].intValue = 1;
configValues["animations:enabled"].intValue = 1;
@@ -222,13 +243,17 @@ void CConfigManager::setDefaultVars() {
configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY;
configValues["input:tablet:transform"].intValue = 0;
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:scroll_event_delay"].intValue = 300;
configValues["binds:workspace_back_and_forth"].intValue = 0;
configValues["binds:allow_workspace_cycles"].intValue = 0;
configValues["binds:focus_preferred_method"].intValue = 0;
configValues["binds:ignore_group_lock"].intValue = 0;
configValues["binds:pass_mouse_when_bound"].intValue = 0;
configValues["binds:scroll_event_delay"].intValue = 300;
configValues["binds:workspace_back_and_forth"].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:ignore_group_lock"].intValue = 0;
configValues["binds:movefocus_cycles_fullscreen"].intValue = 1;
configValues["gestures:workspace_swipe"].intValue = 0;
configValues["gestures:workspace_swipe_fingers"].intValue = 3;
@@ -277,7 +302,9 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
cfgValues["scroll_button_lock"].intValue = 0;
cfgValues["transform"].intValue = 0;
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() {
@@ -347,8 +374,8 @@ void CConfigManager::init() {
}
void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) {
if (configValues.find(COMMAND) == configValues.end()) {
if (COMMAND.find("device:") != 0 /* devices parsed later */ && COMMAND.find("plugin:") != 0 /* plugins parsed later */) {
if (!configValues.contains(COMMAND)) {
if (!COMMAND.starts_with("device:") /* devices parsed later */ && !COMMAND.starts_with("plugin:") /* plugins parsed later */) {
if (COMMAND[0] == '$') {
// register a dynamic var
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;
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 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);
} else if (COMMAND.find("plugin:") == 0) {
} else if (COMMAND.starts_with("plugin:")) {
for (auto& [handle, pMap] : pluginConfigs) {
auto it = std::find_if(pMap->begin(), pMap->end(), [&](const auto& other) { return other.first == COMMAND; });
if (it == pMap->end()) {
@@ -623,11 +650,11 @@ void CConfigManager::handleMonitor(const std::string& command, const std::string
return;
}
if (ARGS[1].find("pref") == 0) {
if (ARGS[1].starts_with("pref")) {
newrule.resolution = Vector2D();
} else if (ARGS[1].find("highrr") == 0) {
} else if (ARGS[1].starts_with("highrr")) {
newrule.resolution = Vector2D(-1, -1);
} else if (ARGS[1].find("highres") == 0) {
} else if (ARGS[1].starts_with("highres")) {
newrule.resolution = Vector2D(-1, -2);
} else if (parseModeLine(ARGS[1], newrule.drmMode)) {
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));
}
if (ARGS[2].find("auto") == 0) {
if (ARGS[2].starts_with("auto")) {
newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX);
} else {
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));
}
if (ARGS[3].find("auto") == 0) {
if (ARGS[3].starts_with("auto")) {
newrule.scale = -1;
} else {
newrule.scale = stof(ARGS[3]);
@@ -810,6 +837,7 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
bool mouse = false;
bool nonConsuming = false;
bool transparent = false;
bool ignoreMods = false;
const auto BINDARGS = command.substr(4);
for (auto& arg : BINDARGS) {
@@ -825,6 +853,8 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
nonConsuming = true;
} else if (arg == 't') {
transparent = true;
} else if (arg == 'i') {
ignoreMods = true;
} else {
parseError = "bind: invalid flag";
return;
@@ -882,12 +912,13 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
if (KEY != "") {
if (isNumber(KEY) && std::stoi(KEY) > 9)
g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent});
else if (KEY.find("code:") == 0 && isNumber(KEY.substr(5)))
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
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) {
return !(RULE != "float" && RULE != "tile" && RULE.find("opacity") != 0 && RULE.find("move") != 0 && RULE.find("size") != 0 && RULE.find("minsize") != 0 &&
RULE.find("maxsize") != 0 && RULE.find("pseudo") != 0 && RULE.find("monitor") != 0 && RULE.find("idleinhibit") != 0 && RULE != "nofocus" && RULE != "noblur" &&
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 != "maximize" && RULE != "keepaspectratio" && RULE.find("animation") != 0 && RULE.find("rounding") != 0 && RULE.find("workspace") != 0 &&
RULE.find("bordercolor") != 0 && RULE != "forcergbx" && RULE != "noinitialfocus" && RULE != "stayfocused" && RULE.find("bordersize") != 0 && RULE.find("xray") != 0 &&
RULE.find("center") != 0 && RULE.find("group") != 0);
return RULE == "float" || RULE == "tile" || RULE.starts_with("opacity") || RULE.starts_with("move") || RULE.starts_with("size") || RULE.starts_with("minsize") ||
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 == "nomaximizerequest" || RULE == "fakefullscreen" || RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" ||
RULE == "maximize" || RULE == "keepaspectratio" || RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") ||
RULE.starts_with("bordercolor") || RULE == "forcergbx" || RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") ||
RULE.starts_with("center") || RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor";
}
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) {
@@ -936,7 +967,7 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
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});
else
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) {
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);
if (!windowRuleValid(RULE) && RULE != "unset") {
@@ -1083,14 +1114,14 @@ void CConfigManager::handleWindowRuleV2(const std::string& command, const std::s
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);
else
m_dWindowRules.push_back(rule);
}
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;
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) {
if (value.find("remove,") == 0) {
if (value.starts_with("remove,")) {
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; }))
updateBlurredLS(TOREMOVE, false);
@@ -1150,7 +1181,10 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
rules = value.substr(WORKSPACE_DELIM + 1);
}
auto assignRule = [&](std::string rule) {
const static std::string ruleOnCreatedEmtpy = "on-created-empty:";
const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length();
auto assignRule = [&](std::string rule) {
size_t delim = std::string::npos;
if ((delim = rule.find("gapsin:")) != std::string::npos)
wsRule.gapsIn = std::stoi(rule.substr(delim + 7));
@@ -1170,6 +1204,10 @@ void CConfigManager::handleWorkspaceRules(const std::string& command, const std:
wsRule.monitor = rule.substr(delim + 8);
else if ((delim = rule.find("default:")) != std::string::npos)
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;
@@ -1239,6 +1277,8 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
std::string line = "";
int linenum = 1;
if (ifs.is_open()) {
auto configCurrentPathBackup = configCurrentPath;
while (std::getline(ifs, line)) {
// Read line by line.
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.";
}
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;
}
@@ -1259,6 +1299,8 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
}
ifs.close();
configCurrentPath = configCurrentPathBackup;
}
}
}
@@ -1322,7 +1364,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
}
} else if (COMMAND == "monitor")
handleMonitor(COMMAND, VALUE);
else if (COMMAND.find("bind") == 0)
else if (COMMAND.starts_with("bind"))
handleBind(COMMAND, VALUE);
else if (COMMAND == "unbind")
handleUnbind(COMMAND, VALUE);
@@ -1346,13 +1388,20 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
handleBlurLS(COMMAND, VALUE);
else if (COMMAND == "wsbind")
handleBindWS(COMMAND, VALUE);
else if (COMMAND.find("env") == 0)
handleEnv(COMMAND, VALUE);
else if (COMMAND.find("plugin") == 0)
else if (COMMAND == "plugin")
handlePlugin(COMMAND, VALUE);
else if (COMMAND.starts_with("env"))
handleEnv(COMMAND, VALUE);
else {
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
needsLayoutRecalc = 2;
// 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);
needsLayoutRecalc = 2;
}
}
if (dynamic) {
@@ -1361,7 +1410,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
// invalidate layouts if they changed
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)
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);
bool found = false;
for (auto& [var, value] : configDynamicVars) {
if (STRAFTERDOLLAR.find(var) == 0) {
if (STRAFTERDOLLAR.starts_with(var)) {
line.replace(dollarPlace, var.length() + 1, value);
found = true;
break;
@@ -1406,7 +1455,7 @@ void CConfigManager::applyUserDefinedVars(std::string& line, const size_t equals
if (!found) {
// maybe env?
for (auto& [var, value] : environmentVariables) {
if (STRAFTERDOLLAR.find(var) == 0) {
if (STRAFTERDOLLAR.starts_with(var)) {
line.replace(dollarPlace, var.length() + 1, value);
break;
}
@@ -1486,6 +1535,8 @@ void CConfigManager::parseLine(std::string& line) {
}
void CConfigManager::loadConfigLoadVars() {
EMIT_HOOK_EVENT("preConfigReload", nullptr);
Debug::log(LOG, "Reloading the config!");
parseError = ""; // reset the error
currentCategory = ""; // reset the category
@@ -1572,7 +1623,7 @@ void CConfigManager::loadConfigLoadVars() {
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;
}
@@ -1733,6 +1784,10 @@ float CConfigManager::getFloat(const std::string& v) {
return getConfigValueSafe(v).floatValue;
}
Vector2D CConfigManager::getVec(const std::string& v) {
return getConfigValueSafe(v).vecValue;
}
std::string CConfigManager::getString(const std::string& v) {
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;
}
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) {
auto VAL = getConfigValueSafeDevice(dev, v, fallback).strValue;
@@ -1767,6 +1826,10 @@ void CConfigManager::setFloat(const std::string& v, float 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) {
configValues[v].strValue = val;
}
@@ -1776,7 +1839,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const std::string& name, const st
for (auto& r : m_dMonitorRules) {
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('(')))))) {
found = &r;
break;
@@ -1804,7 +1867,13 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const std::string& name, const st
}
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())
return SWorkspaceRule{};
return *IT;
@@ -1829,7 +1898,7 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
// check if we have a matching rule
if (!rule.v2) {
try {
if (rule.szValue.find("title:") == 0) {
if (rule.szValue.starts_with("title:")) {
// we have a title rule.
std::regex RULECHECK(rule.szValue.substr(6));
@@ -1887,7 +1956,7 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
if (!PWORKSPACE)
continue;
if (rule.szWorkspace.find("name:") == 0) {
if (rule.szWorkspace.starts_with("name:")) {
if (PWORKSPACE->m_szName != rule.szWorkspace.substr(5))
continue;
} else {
@@ -1945,7 +2014,7 @@ std::vector<SLayerRule> CConfigManager::getMatchingRules(SLayerSurface* pLS) {
return returns;
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)
continue;
} else {
@@ -2001,7 +2070,7 @@ void CConfigManager::performMonitorReload() {
bool overAgain = false;
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (!m->output)
if (!m->output || m->isUnsafeFallback)
continue;
auto rule = getMonitorRuleFor(m->szName, m->output->description ? m->output->description : "");
@@ -2020,9 +2089,6 @@ void CConfigManager::performMonitorReload() {
if (overAgain)
performMonitorReload();
if (!g_pCompositor->m_vMonitors.empty()) // reset unsafe state if we have monitors
g_pCompositor->m_bUnsafeState = false;
m_bWantsMonitorReload = false;
EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr);
@@ -2070,9 +2136,7 @@ bool CConfigManager::deviceConfigExists(const std::string& dev) {
auto copy = dev;
std::replace(copy.begin(), copy.end(), ' ', '-');
const auto it = deviceConfigs.find(copy);
return it != deviceConfigs.end();
return deviceConfigs.contains(copy);
}
bool CConfigManager::shouldBlurLS(const std::string& ns) {
@@ -2087,15 +2151,13 @@ bool CConfigManager::shouldBlurLS(const std::string& ns) {
void CConfigManager::ensureMonitorStatus() {
for (auto& rm : g_pCompositor->m_vRealMonitors) {
if (!rm->output)
if (!rm->output || rm->isUnsafeFallback)
continue;
auto rule = getMonitorRuleFor(rm->szName, rm->output->description ? rm->output->description : "");
if (rule.disabled == rm->m_bEnabled) {
rm->m_pThisWrap = &rm;
if (rule.disabled == rm->m_bEnabled)
g_pHyprRenderer->applyMonitorRule(rm.get(), &rule);
}
}
}
@@ -2193,7 +2255,7 @@ CMonitor* CConfigManager::getBoundMonitorForWS(const std::string& wsname) {
std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname) {
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) {
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) {
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) {

View File

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

View File

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

View File

@@ -1,7 +1,6 @@
#include "CrashReporter.hpp"
#include <random>
#include <sys/utsname.h>
#include <execinfo.h>
#include <fstream>
#include <signal.h>
@@ -14,19 +13,19 @@
std::string getRandomMessage() {
const std::vector<std::string> MESSAGES = {"Sorry, didn't mean to...",
"This was an accident, I swear!",
"Calm down, it was a misinput! MISINPUT!",
"Oops",
"Vaxry is going to be upset.",
"Who tried dividing by zero?!",
"Maybe you should try dusting your PC in the meantime?",
"I tried so hard, and got so far...",
"I don't feel so good...",
"*thud*",
"Well this is awkward.",
"\"stable\"",
"I hope you didn't have any unsaved progress.",
"All these computers..."};
"This was an accident, I swear!",
"Calm down, it was a misinput! MISINPUT!",
"Oops",
"Vaxry is going to be upset.",
"Who tried dividing by zero?!",
"Maybe you should try dusting your PC in the meantime?",
"I tried so hard, and got so far...",
"I don't feel so good...",
"*thud*",
"Well this is awkward.",
"\"stable\"",
"I hope you didn't have any unsaved progress.",
"All these computers..."};
std::random_device dev;
std::mt19937 engine(dev());
@@ -130,7 +129,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
std::ofstream ofs;
std::string path;
if (!CACHE_HOME) {
if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
@@ -139,7 +138,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc);
} else if (CACHE_HOME) {
} else {
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) {
std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
std::filesystem::permissions(std::string(CACHE_HOME) + "/hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
@@ -147,8 +146,6 @@ void CrashReporter::createAndSaveCrash(int sig) {
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc);
} else {
return;
}
ofs << finalCrashReport;

View File

@@ -63,14 +63,16 @@ std::string monitorsRequest(HyprCtl::eHyprCtlOutputFormat format) {
"transform": {},
"focused": {},
"dpmsStatus": {},
"vrr": {}
"vrr": {},
"activelyTearing": {}
}},)#",
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,
(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,
(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);
@@ -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 "
"workspace: {} ({})\n\treserved: {} "
"{} {} {}\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->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,
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->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)
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;
bool first = true;
for (auto& gw : groupMembers) {
if (first)
first = false;
else
result << comma;
CWindow* head = w->getGroupHead();
CWindow* curr = head;
while (true) {
if (isJson)
result << std::format("\"0x{:x}\"", (uintptr_t)gw);
result << std::format("\"0x{:x}\"", (uintptr_t)curr);
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();
}
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) {
return std::format(
R"#({{
@@ -155,7 +158,8 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
"fullscreenMode": {},
"fakeFullscreen": {},
"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,
(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(),
((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_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 {
return std::format(
"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\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,
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID,
(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,
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),
(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": {},
"name": "{}",
"monitor": "{}",
"monitorID": {},
"windows": {},
"hasfullscreen": {},
"lastwindow": "0x{:x}",
"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) : "");
} 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,
PMONITOR ? PMONITOR->szName : "?", g_pCompositor->getWindowsOnWorkspace(w->m_iID), (int)w->m_bHasFullscreenWindow, (uintptr_t)PLASTW,
PLASTW ? PLASTW->m_szTitle : "");
return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID,
w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", g_pCompositor->getWindowsOnWorkspace(w->m_iID),
(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) {
if (!g_pCompositor->m_pLastMonitor)
return "unsafe state";
std::string result = "";
auto w = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
if (!w)
return "internal error";
return getWorkspaceData(w, format);
}
@@ -254,6 +305,26 @@ std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
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) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
@@ -835,7 +906,8 @@ std::string dispatchSetCursor(std::string request) {
std::string theme = "";
for (size_t i = 1; i < vars.size() - 1; ++i)
theme += vars[i] + " ";
theme.pop_back();
if (!theme.empty())
theme.pop_back();
int size = 0;
try {
@@ -951,7 +1023,7 @@ std::string dispatchSetProp(std::string request) {
bool lock = false;
if (vars.size() > 4) {
if (vars[4].find("lock") == 0) {
if (vars[4].starts_with("lock")) {
lock = true;
}
}
@@ -1001,6 +1073,10 @@ std::string dispatchSetProp(std::string request) {
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "keepaspectratio") {
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 {
return "prop not found";
}
@@ -1247,6 +1323,8 @@ std::string getReply(std::string request) {
return monitorsRequest(format);
else if (request == "workspaces")
return workspacesRequest(format);
else if (request == "workspacerules")
return workspaceRulesRequest(format);
else if (request == "activeworkspace")
return activeWorkspaceRequest(format);
else if (request == "clients")
@@ -1259,7 +1337,7 @@ std::string getReply(std::string request) {
return layersRequest(format);
else if (request == "version")
return versionRequest(format);
else if (request.find("reload") == 0)
else if (request.starts_with("reload"))
return reloadRequest(request);
else if (request == "devices")
return devicesRequest(format);
@@ -1273,27 +1351,27 @@ std::string getReply(std::string request) {
return globalShortcutsRequest(format);
else if (request == "animations")
return animationsRequest(format);
else if (request.find("plugin") == 0)
else if (request.starts_with("plugin"))
return dispatchPlugin(request);
else if (request.find("notify") == 0)
else if (request.starts_with("notify"))
return dispatchNotify(request);
else if (request.find("setprop") == 0)
else if (request.starts_with("setprop"))
return dispatchSetProp(request);
else if (request.find("seterror") == 0)
else if (request.starts_with("seterror"))
return dispatchSeterror(request);
else if (request.find("switchxkblayout") == 0)
else if (request.starts_with("switchxkblayout"))
return switchXKBLayoutRequest(request);
else if (request.find("output") == 0)
else if (request.starts_with("output"))
return dispatchOutput(request);
else if (request.find("dispatch") == 0)
else if (request.starts_with("dispatch"))
return dispatchRequest(request);
else if (request.find("keyword") == 0)
else if (request.starts_with("keyword"))
return dispatchKeyword(request);
else if (request.find("setcursor") == 0)
else if (request.starts_with("setcursor"))
return dispatchSetCursor(request);
else if (request.find("getoption") == 0)
else if (request.starts_with("getoption"))
return dispatchGetOption(request, format);
else if (request.find("[[BATCH]]") == 0)
else if (request.starts_with("[[BATCH]]"))
return dispatchBatch(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);
wlr_box pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y};
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
}

View File

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

View File

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

View File

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

View File

@@ -10,6 +10,12 @@ void Debug::init(const std::string& IS) {
}
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;
std::ofstream ofs;

View File

@@ -1,10 +1,10 @@
#pragma once
#include <string>
#include <wlr/util/log.h>
#include <format>
#include <iostream>
#include <fstream>
#include <chrono>
#include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp"
#define LOGMESSAGESIZE 1024
@@ -79,4 +79,4 @@ namespace Debug {
}
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
};
};

View File

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

View File

@@ -95,8 +95,8 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
PMONITOR->scheduledRecalc = true;
// and damage
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
}
@@ -142,7 +142,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive &&
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
@@ -157,8 +157,8 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
@@ -171,7 +171,8 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
EMIT_HOOK_EVENT("openLayer", layersurface);
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
}
void Events::listener_unmapLayerSurface(void* owner, void* data) {
@@ -246,8 +247,8 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
}
}
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y,
@@ -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)
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
wlr_box geomFixed = {layersurface->geometry.x, layersurface->geometry.y, layersurface->geometry.width, layersurface->geometry.height};
CBox geomFixed = {layersurface->geometry.x, layersurface->geometry.y, layersurface->geometry.width, layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
// fix if it changed its mon
@@ -342,5 +343,6 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
g_pHyprRenderer->damageSurface(layersurface->layerSurface->surface, layersurface->position.x, layersurface->position.y);
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
g_pCompositor->setPreferredScaleForSurface(layersurface->layerSurface->surface, PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(layersurface->layerSurface->surface, PMONITOR->transform);
}

View File

@@ -237,3 +237,43 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
g_pInputManager->processMouseRequest(E);
}
void Events::listener_newTearingHint(wl_listener* listener, void* data) {
const auto TCTL = (wlr_tearing_control_v1*)data;
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface);
if (!PWINDOW) {
Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
return;
}
Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)data);
const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
NEWCTRL->hyprListener_destroy.initCallback(
&NEWCTRL->pWlrHint->events.destroy,
[&](void* owner, void* data) {
Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
},
NEWCTRL, "TearingController");
NEWCTRL->hyprListener_set.initCallback(
&NEWCTRL->pWlrHint->events.set_hint,
[&](void* owner, void* data) {
const auto TEARINGHINT = (STearingController*)owner;
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
if (PWINDOW) {
PWINDOW->m_bTearingHint = TEARINGHINT->pWlrHint->hint;
Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->hint);
}
},
NEWCTRL, "TearingController");
}

View File

@@ -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);
wlr_box BOX;
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, &BOX);
CBox BOX;
wlr_output_layout_get_box(g_pCompositor->m_sWLROutputLayout, m->output, BOX.pWlr());
BOX.applyFromWlr();
//m->vecSize.x = BOX.width;
// m->vecSize.y = BOX.height;
@@ -67,45 +68,31 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
return;
}
if (g_pCompositor->m_bUnsafeState)
Debug::log(WARN, "Recovering from an unsafe state. May you be lucky.");
// add it to real
std::shared_ptr<CMonitor>* PNEWMONITORWRAP = nullptr;
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();
PNEWMONITOR->isUnsafeFallback = FALLBACK;
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
if (!FALLBACK)
PNEWMONITOR->onConnect(false);
PNEWMONITOR->output = OUTPUT;
PNEWMONITOR->m_pThisWrap = PNEWMONITORWRAP;
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
return;
PNEWMONITOR->onConnect(false);
// ready to process if we have a real monitor
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR;
// ready to process cuz we have a monitor
if (PNEWMONITOR->m_bEnabled) {
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_bUnsafeState = false;
}
g_pCompositor->m_bReadyToProcess = true;
g_pConfigManager->m_bWantsMonitorReload = true;
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) {
Debug::log(WARN, "Attempted to render frame on inactive session!");
if (g_pCompositor->m_bUnsafeState)
g_pConfigManager->performMonitorReload();
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
return m->output != g_pCompositor->m_pUnsafeOutput->output;
})) {
// restore from unsafe state
g_pCompositor->leaveUnsafeState();
}
return; // cannot draw on session inactive (different tty)
}
@@ -140,12 +131,25 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (!PMONITOR->m_bEnabled)
return;
g_pHyprRenderer->recheckSolitaryForMonitor(PMONITOR);
PMONITOR->tearingState.busy = false;
if (PMONITOR->tearingState.activelyTearing && PMONITOR->solitaryClient /* can be invalidated by a recheck */) {
if (!PMONITOR->tearingState.frameScheduledWhileBusy)
return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render?
PMONITOR->tearingState.nextRenderTorn = true;
PMONITOR->tearingState.frameScheduledWhileBusy = false;
}
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
PMONITOR->lastPresentationTimer.reset();
if (*PENABLERAT) {
if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) {
if (!PMONITOR->RATScheduled) {
// render
g_pHyprRenderer->renderMonitor(PMONITOR);
@@ -226,7 +230,7 @@ void Events::listener_monitorCommit(void* owner, void* data) {
const auto E = (wlr_output_event_commit*)data;
if (E->committed & WLR_OUTPUT_STATE_BUFFER) {
if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) {
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
}

View File

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

View File

@@ -46,6 +46,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
static auto* const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex")->strValue;
static auto* const PNEWTAKESOVERFS = &g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen")->intValue;
auto PMONITOR = g_pCompositor->m_pLastMonitor;
const auto PWORKSPACE =
@@ -95,7 +96,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PWORKSPACE->m_bDefaultPseudo) {
PWINDOW->m_bIsPseudotiled = true;
wlr_box desiredGeometry = {0};
CBox desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry);
PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
}
@@ -116,7 +117,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW);
for (auto& r : WINDOWRULES) {
if (r.szRule.find("monitor") == 0) {
if (r.szRule.starts_with("monitor")) {
try {
const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' ')));
@@ -150,7 +151,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
} else if (r.szRule.find("workspace") == 0) {
} else if (r.szRule.starts_with("workspace")) {
// check if it isnt unset
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 = "";
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;
} else if (r.szRule.find("tile") == 0) {
} else if (r.szRule.starts_with("tile")) {
PWINDOW->m_bIsFloating = false;
} else if (r.szRule.find("pseudo") == 0) {
} else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.find("nofocus") == 0) {
} else if (r.szRule.starts_with("nofocus")) {
PWINDOW->m_bNoFocus = true;
} else if (r.szRule.find("noinitialfocus") == 0) {
} else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.find("nofullscreenrequest") == 0) {
} else if (r.szRule.starts_with("nofullscreenrequest")) {
PWINDOW->m_bNoFullscreenRequest = true;
} else if (r.szRule.find("nomaximizerequest") == 0) {
} else if (r.szRule.starts_with("nomaximizerequest")) {
PWINDOW->m_bNoMaximizeRequest = true;
} else if (r.szRule == "fullscreen") {
requestsFullscreen = true;
@@ -198,7 +199,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
overridingNoMaximize = true;
} else if (r.szRule == "stayfocused") {
PWINDOW->m_bStayFocused = true;
} else if (r.szRule.find("group") == 0) {
} else if (r.szRule.starts_with("group")) {
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
continue;
@@ -245,7 +246,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
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);
if (IDLERULE == "none") {
@@ -263,13 +264,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->applyDynamicRule(r);
}
CWindow* pFullscreenWindow = nullptr;
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
pFullscreenWindow = PFULLWINDOW;
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, PWORKSPACE->m_efFullscreenMode);
}
PWINDOW->updateSpecialRenderData();
// disallow tiled pinned
@@ -279,7 +273,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
const CVarList WORKSPACEARGS = CVarList(requestedWorkspace, 0, ' ');
if (!WORKSPACEARGS[0].empty()) {
if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].find("silent") == 0)
if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].starts_with("silent"))
workspaceSilent = true;
std::string requestedWorkspaceName;
@@ -315,7 +309,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// size and move rules
for (auto& r : WINDOWRULES) {
if (r.szRule.find("size") == 0) {
if (r.szRule.starts_with("size")) {
try {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
@@ -337,7 +331,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->setHidden(false);
} 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 {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
@@ -351,7 +345,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->setHidden(false);
} 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 {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
@@ -365,16 +359,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->setHidden(false);
} 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 {
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)
value = value.substr(value.find_first_of(' ') + 1);
const bool CURSOR = value.find("cursor") == 0;
const bool CURSOR = value.starts_with("cursor");
if (CURSOR)
value = value.substr(value.find_first_of(' ') + 1);
@@ -385,7 +379,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
int posX = 0;
int posY = 0;
if (POSXSTR.find("100%-") == 0) {
if (POSXSTR.starts_with("100%-")) {
const auto POSXRAW = POSXSTR.substr(5);
posX =
PMONITOR->vecSize.x - (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x);
@@ -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);
posY =
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);
} 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();
const auto ARGS = CVarList(r.szRule, 2, ' ');
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);
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive)
PWINDOW->m_bNoInitialFocus = true;
if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
if (*PNEWTAKESOVERFS == 0)
PWINDOW->m_bNoInitialFocus = true;
else if (*PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID);
else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
requestsMaximize = true;
else
requestsFullscreen = true;
}
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus &&
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
@@ -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_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW,
"XDG Window Late");
PWINDOW->hyprListener_ackConfigure.initCallback(&PWINDOW->m_uSurface.xdg->events.ack_configure, &Events::listener_ackConfigure, PWINDOW, "XDG Window Late");
} else {
PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW,
"XWayland Window Late");
@@ -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
g_pInputManager->recheckIdleInhibitorStatus();
@@ -642,8 +643,18 @@ void Events::listener_mapWindow(void* owner, void* data) {
// recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
// avoid this window being visible
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating)
PWINDOW->m_fAlpha.setValueAndWarp(0.f);
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == g_pCompositor->m_pLastWindow)
g_pInputManager->simulateMouseMovement();
// fix some xwayland apps that don't behave nicely
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
}
void Events::listener_unmapWindow(void* owner, void* data) {
@@ -657,6 +668,13 @@ void Events::listener_unmapWindow(void* owner, void* data) {
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)});
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
@@ -672,6 +690,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->hyprListener_requestMove.removeCallback();
PWINDOW->hyprListener_requestResize.removeCallback();
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
PWINDOW->hyprListener_ackConfigure.removeCallback();
} else {
Debug::log(LOG, "Unregistered late callbacks XWL");
PWINDOW->hyprListener_fullscreenWindow.removeCallback();
@@ -685,13 +704,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (PWINDOW->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR) {
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
}
// Allow the renderer to catch the last frame.
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
@@ -731,13 +743,17 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE);
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow) {
if (!PWINDOWCANDIDATE)
g_pInputManager->simulateMouseMovement();
else
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
} else {
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
if (g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal()) == PWINDOWCANDIDATE)
g_pInputManager->simulateMouseMovement();
// CWindow::onUnmap will remove this window's active status, but we can't really do it above.
if (PWINDOW == g_pCompositor->m_pLastWindow || !g_pCompositor->m_pLastWindow) {
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ","});
EMIT_HOOK_EVENT("activeWindow", (CWindow*)nullptr);
}
} else {
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
@@ -774,12 +790,33 @@ void Events::listener_unmapWindow(void* owner, void* data) {
PWINDOW->onUnmap();
}
void Events::listener_ackConfigure(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
const auto E = (wlr_xdg_surface_configure*)data;
// find last matching serial
const auto SERIAL = std::find_if(PWINDOW->m_vPendingSizeAcks.rbegin(), PWINDOW->m_vPendingSizeAcks.rend(), [&](const auto& e) { return e.first == E->serial; });
if (SERIAL == PWINDOW->m_vPendingSizeAcks.rend())
return;
PWINDOW->m_pPendingSizeAck = *SERIAL;
std::erase_if(PWINDOW->m_vPendingSizeAcks, [&](const auto& el) { return el.first == SERIAL->first; });
}
void Events::listener_commitWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bMappedX11 || PWINDOW->isHidden() || (PWINDOW->m_bIsX11 && !PWINDOW->m_bMappedX11))
return;
if (PWINDOW->m_bIsX11)
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
else if (PWINDOW->m_pPendingSizeAck.has_value()) {
PWINDOW->m_vReportedSize = PWINDOW->m_pPendingSizeAck->second;
PWINDOW->m_pPendingSizeAck.reset();
}
PWINDOW->updateSurfaceOutputs();
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
@@ -839,8 +876,8 @@ void Events::listener_destroyWindow(void* owner, void* data) {
PWINDOW->m_bReadyToDelete = true;
if (!PWINDOW->m_bFadingOut) {
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
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) {
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
PWINDOW->m_vReportedSize = {E->width, E->height};
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;
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
}
}
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
@@ -1042,6 +1083,8 @@ void Events::listener_configureX11(void* owner, void* data) {
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->updateWindowDecos();
PWINDOW->m_vReportedSize = {E->width, E->height};
}
void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
@@ -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));
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
}
}
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();

View File

@@ -6,6 +6,7 @@
#include "Vector2D.hpp"
#include "Color.hpp"
#include "../macros.hpp"
#include "../debug/Log.hpp"
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 {
public:
CColor();
CColor(float, float, float, float);
CColor(float r, float g, float b, float a);
CColor(uint64_t);
float r = 0, g = 0, b = 0, a = 1.f;
@@ -27,4 +27,8 @@ class CColor {
bool operator==(const CColor& c2) const {
return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
}
CColor stripA() const {
return {r, g, b, 1};
}
};

View File

@@ -2,11 +2,14 @@
#include "../defines.hpp"
#include <algorithm>
#include "../Compositor.hpp"
#include <optional>
#include <set>
#include <sys/utsname.h>
#include <iomanip>
#include <sstream>
#ifdef HAS_EXECINFO
#include <execinfo.h>
#endif
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sysctl.h>
@@ -182,13 +185,6 @@ std::string escapeJSONStrings(const std::string& str) {
return oss.str();
}
void scaleBox(wlr_box* box, float scale) {
box->width = std::round(box->width * scale);
box->height = std::round(box->height * scale);
box->x = std::round(box->x * scale);
box->y = std::round(box->y * scale);
}
std::string removeBeginEndSpacesTabs(std::string str) {
if (str.empty())
return str;
@@ -246,9 +242,13 @@ bool isDirection(const std::string& arg) {
return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b";
}
bool isDirection(const char& arg) {
return arg == 'l' || arg == 'r' || arg == 'u' || arg == 'd' || arg == 't' || arg == 'b';
}
int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int result = INT_MAX;
if (in.find("special") == 0) {
if (in.starts_with("special")) {
outName = "special";
if (in.length() > 8) {
@@ -262,7 +262,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
}
return SPECIAL_WORKSPACE_START;
} else if (in.find("name:") == 0) {
} else if (in.starts_with("name:")) {
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
if (!WORKSPACE) {
@@ -271,14 +271,14 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
result = WORKSPACE->m_iID;
}
outName = WORKSPACENAME;
} else if (in.find("empty") == 0) {
} else if (in.starts_with("empty")) {
int id = 0;
while (++id < INT_MAX) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0))
return id;
}
} else if (in.find("prev") == 0) {
} else if (in.starts_with("prev")) {
if (!g_pCompositor->m_pLastMonitor)
return INT_MAX;
@@ -389,12 +389,12 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int beginID = finalWSID;
int curID = finalWSID;
while (--curID > 0 && remainingWSes > 0) {
if (invalidWSes.find(curID) == invalidWSes.end()) {
if (!invalidWSes.contains(curID)) {
remainingWSes--;
}
finalWSID = curID;
}
if (finalWSID <= 0 || invalidWSes.find(finalWSID) != invalidWSes.end()) {
if (finalWSID <= 0 || invalidWSes.contains(finalWSID)) {
if (namedWSes.size()) {
// Go to the named workspaces
// Need remainingWSes more
@@ -414,7 +414,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
if (walkDir == '+') {
int curID = finalWSID;
while (++curID < INT32_MAX && remainingWSes > 0) {
if (invalidWSes.find(curID) == invalidWSes.end()) {
if (!invalidWSes.contains(curID)) {
remainingWSes--;
}
finalWSID = curID;
@@ -501,6 +501,43 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
return result;
}
std::optional<std::string> cleanCmdForWorkspace(const std::string& inWorkspaceName, std::string dirtyCmd) {
std::string cmd = removeBeginEndSpacesTabs(dirtyCmd);
if (!cmd.empty()) {
std::string rules;
const std::string workspaceRule = "workspace " + inWorkspaceName;
if (cmd[0] == '[') {
const int closingBracketIdx = cmd.find_last_of(']');
auto tmpRules = cmd.substr(1, closingBracketIdx - 1);
cmd = cmd.substr(closingBracketIdx + 1);
auto rulesList = CVarList(tmpRules, 0, ';');
bool hadWorkspaceRule = false;
rulesList.map([&](std::string& rule) {
if (rule.find("workspace") == 0) {
rule = workspaceRule;
hadWorkspaceRule = true;
}
});
if (!hadWorkspaceRule)
rulesList.append(workspaceRule);
rules = "[" + rulesList.join(";") + "]";
} else {
rules = "[" + workspaceRule + "]";
}
return std::optional<std::string>(rules + " " + cmd);
}
return std::nullopt;
}
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) {
const float DX = std::max({0.0, p1.x - vec.x, vec.x - p2.x});
const float DY = std::max({0.0, p1.y - vec.y, vec.y - p2.y});
@@ -626,11 +663,11 @@ int64_t getPPIDof(int64_t pid) {
}
int64_t configStringToInt(const std::string& VALUE) {
if (VALUE.find("0x") == 0) {
if (VALUE.starts_with("0x")) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
return stol(VALUEWITHOUTHEX, nullptr, 16);
} else if (VALUE.find("rgba(") == 0 && VALUE.find(')') == VALUE.length() - 1) {
} else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) {
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
@@ -642,7 +679,7 @@ int64_t configStringToInt(const std::string& VALUE) {
// now we need to RGBA -> ARGB. The config holds ARGB only.
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
} else if (VALUE.find("rgb(") == 0 && VALUE.find(')') == VALUE.length() - 1) {
} else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) {
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
@@ -653,9 +690,9 @@ int64_t configStringToInt(const std::string& VALUE) {
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
return RGB + 0xFF000000; // 0xFF for opaque
} else if (VALUE.find("true") == 0 || VALUE.find("on") == 0 || VALUE.find("yes") == 0) {
} else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) {
return 1;
} else if (VALUE.find("false") == 0 || VALUE.find("off") == 0 || VALUE.find("no") == 0) {
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
return 0;
}
return std::stoll(VALUE);
@@ -689,9 +726,10 @@ std::string replaceInString(std::string subject, const std::string& search, cons
std::vector<SCallstackFrameInfo> getBacktrace() {
std::vector<SCallstackFrameInfo> callstack;
void* bt[1024];
size_t btSize;
char** btSymbols;
#ifdef HAS_EXECINFO
void* bt[1024];
size_t btSize;
char** btSymbols;
btSize = backtrace(bt, 1024);
btSymbols = backtrace_symbols(bt, btSize);
@@ -699,6 +737,9 @@ std::vector<SCallstackFrameInfo> getBacktrace() {
for (size_t i = 0; i < btSize; ++i) {
callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}});
}
#else
callstack.emplace_back(SCallstackFrameInfo{nullptr, "configuration does not support execinfo.h"});
#endif
return callstack;
}
@@ -706,4 +747,21 @@ std::vector<SCallstackFrameInfo> getBacktrace() {
void throwError(const std::string& err) {
Debug::log(CRIT, "Critical error thrown: {}", err);
throw std::runtime_error(err);
}
uint32_t drmFormatToGL(uint32_t drm) {
switch (drm) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
#ifdef GLES2
return GL_RGB10_A2_EXT;
#else
return GL_RGB10_A2;
#endif
default: return GL_RGBA;
}
UNREACHABLE();
return GL_RGBA;
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <optional>
#include <string>
#include <wayland-server.h>
#include <wlr/util/box.h>
@@ -15,11 +16,12 @@ struct SCallstackFrameInfo {
std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
std::string escapeJSONStrings(const std::string& str);
void scaleBox(wlr_box*, float);
std::string removeBeginEndSpacesTabs(std::string);
bool isNumber(const std::string&, bool allowfloat = false);
bool isDirection(const std::string&);
bool isDirection(const char&);
int getWorkspaceIDFromString(const std::string&, std::string&);
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
void logSystemInfo();
std::string execAndGet(const char*);
@@ -31,6 +33,7 @@ double normalizeAngleRad(double ang);
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err);
uint32_t drmFormatToGL(uint32_t drm);
template <typename... 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_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this);
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
if (m_bEnabled) {
wlr_output_enable(output, 1);
wlr_output_commit(output);
@@ -107,20 +109,20 @@ void CMonitor::onConnect(bool noRule) {
m_bRenderingInitPassed = true;
}
if (!m_pThisWrap) {
std::shared_ptr<CMonitor>* thisWrapper = nullptr;
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
m_pThisWrap = &m;
break;
}
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
thisWrapper = &m;
break;
}
}
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end()) {
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
}
RASSERT(thisWrapper->get(), "CMonitor::onConnect: Had no wrapper???");
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_vMonitors.end())
g_pCompositor->m_vMonitors.push_back(*thisWrapper);
m_bEnabled = true;
@@ -130,6 +132,8 @@ void CMonitor::onConnect(bool noRule) {
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
wlr_output_commit(output);
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
@@ -150,8 +154,6 @@ void CMonitor::onConnect(bool noRule) {
if (scale < 0.1)
scale = getDefaultScale();
m_pThisWrap = nullptr;
forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
//
@@ -182,6 +184,8 @@ void CMonitor::onConnect(bool noRule) {
g_pCompositor->setActiveMonitor(this);
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
g_pCompositor->scheduleFrameForMonitor(this);
}
void CMonitor::onDisconnect() {
@@ -219,9 +223,6 @@ void CMonitor::onDisconnect() {
g_pConfigManager->m_bWantsMonitorReload = true;
}
m_bEnabled = false;
m_bRenderingInitPassed = false;
hyprListener_monitorFrame.removeCallback();
hyprListener_monitorDamage.removeCallback();
hyprListener_monitorNeedsFrame.removeCallback();
@@ -243,9 +244,12 @@ void CMonitor::onDisconnect() {
if (!BACKUPMON) {
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) {
// snap cursor
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
std::deque<CWorkspace*> wspToMove;
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());
}
}
@@ -313,14 +317,14 @@ void CMonitor::addDamage(const CRegion* rg) {
addDamage(const_cast<CRegion*>(rg)->pixman());
}
void CMonitor::addDamage(const wlr_box* box) {
void CMonitor::addDamage(const CBox* box) {
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
wlr_damage_ring_add_whole(&damage);
g_pCompositor->scheduleFrameForMonitor(this);
}
if (wlr_damage_ring_add_box(&damage, box))
if (wlr_damage_ring_add_box(&damage, const_cast<CBox*>(box)->pWlr()))
g_pCompositor->scheduleFrameForMonitor(this);
}
@@ -412,19 +416,22 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
vecPosition = RULE.offset;
// push to mvmonitors
if (!m_pThisWrap) {
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
m_pThisWrap = &m;
break;
}
std::shared_ptr<CMonitor>* thisWrapper = nullptr;
// find the wrap
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->ID == ID) {
thisWrapper = &m;
break;
}
}
RASSERT(thisWrapper->get(), "CMonitor::setMirror: Had no wrapper???");
if (std::find_if(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& other) { return other.get() == this; }) ==
g_pCompositor->m_vMonitors.end()) {
g_pCompositor->m_vMonitors.push_back(*m_pThisWrap);
g_pCompositor->m_vMonitors.push_back(*thisWrapper);
}
setupDefaultWS(RULE);
@@ -552,6 +559,8 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
g_pHyprRenderer->damageMonitor(this);
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
g_pConfigManager->ensureVRR(this);
}
void CMonitor::changeWorkspace(const int& id, bool internal) {

View File

@@ -61,10 +61,12 @@ class CMonitor {
bool gammaChanged = false;
float xwaylandScale = 1.f;
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
uint32_t drmFormat = DRM_FORMAT_INVALID;
bool isUnsafeFallback = false;
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false;
@@ -81,6 +83,18 @@ class CMonitor {
CRegion lastFrameDamage; // stores last frame damage
// for tearing
CWindow* solitaryClient = nullptr;
struct {
bool canTear = false;
bool nextRenderTorn = false;
bool activelyTearing = false;
bool busy = false;
bool frameScheduledWhileBusy = false;
} tearingState;
// for the special workspace. 0 means not open.
int specialWorkspaceID = 0;
@@ -95,24 +109,23 @@ class CMonitor {
DYNLISTENER(monitorBind);
// methods
void onConnect(bool noRule);
void onDisconnect();
void addDamage(const pixman_region32_t* rg);
void addDamage(const CRegion* rg);
void addDamage(const wlr_box* box);
void setMirror(const std::string&);
bool isMirror();
float getDefaultScale();
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false);
void changeWorkspace(const int& id, bool internal = false);
void setSpecialWorkspace(CWorkspace* const pWorkspace);
void setSpecialWorkspace(const int& id);
void moveTo(const Vector2D& pos);
Vector2D middle();
void onConnect(bool noRule);
void onDisconnect();
void addDamage(const pixman_region32_t* rg);
void addDamage(const CRegion* rg);
void addDamage(const CBox* box);
void setMirror(const std::string&);
bool isMirror();
float getDefaultScale();
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false);
void changeWorkspace(const int& id, bool internal = false);
void setSpecialWorkspace(CWorkspace* const pWorkspace);
void setSpecialWorkspace(const int& id);
void moveTo(const Vector2D& pos);
Vector2D middle();
std::shared_ptr<CMonitor>* m_pThisWrap = nullptr;
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
// For the list lookup

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
#pragma once
#include <functional>
#include <vector>
#include <string>
#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;
void map(std::function<void(std::string&)> func) {
for (auto& s : m_vArgs)
func(s);
}
void append(const std::string arg) {
m_vArgs.emplace_back(arg);
}
std::string operator[](const size_t& idx) const {
if (idx >= m_vArgs.size())
return "";

View File

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

View File

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

View File

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

View File

@@ -33,7 +33,7 @@ struct SLayerSurface {
DYNLISTENER(commitLayerSurface);
DYNLISTENER(newPopup);
wlr_box geometry = {0, 0, 0, 0};
CBox geometry = {0, 0, 0, 0};
Vector2D position;
zwlr_layer_shell_v1_layer layer;
@@ -65,12 +65,12 @@ class CMonitor;
struct SRenderData {
CMonitor* pMonitor;
timespec* when;
int x, y;
double x, y;
// for iters
void* data = nullptr;
wlr_surface* surface = nullptr;
int w, h;
double w, h;
// for rounding
bool dontRound = true;
@@ -168,18 +168,19 @@ struct SConstraint {
bool active = false;
bool hintSet = false;
Vector2D positionHint = {-1, -1}; // the position hint, but will be set to the current cursor pos if not set.
bool hintSet = false;
Vector2D positionHint = {-1, -1}; // the position hint, but will use cursorPosOnActivate if unset
Vector2D cursorPosOnActivate = {-1, -1};
DYNLISTENER(setConstraintRegion);
DYNLISTENER(destroyConstraint);
CRegion getLogicCoordsRegion();
CRegion getLogicCoordsRegion();
Vector2D getLogicConstraintPos();
Vector2D getLogicConstraintSize();
bool operator==(const SConstraint& b) const {
return constraint == b.constraint;
bool operator==(const SConstraint& b) const {
return constraint == b.constraint;
}
};
@@ -392,3 +393,14 @@ struct SSwitchDevice {
return pWlrDevice == other.pWlrDevice;
}
};
struct STearingController {
wlr_tearing_control_v1* pWlrHint = nullptr;
DYNLISTENER(set);
DYNLISTENER(destroy);
bool operator==(const STearingController& other) {
return pWlrHint == other.pWlrHint;
}
};

View File

@@ -2,11 +2,18 @@
#include "MiscFunctions.hpp"
#include <string>
#include "../debug/Log.hpp"
#include "Watchdog.hpp"
void handleWrapped(wl_listener* listener, void* data) {
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
pWrap->m_pSelf->emit(data);
g_pWatchdog->startWatching();
try {
pWrap->m_pSelf->emit(data);
} catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); }
g_pWatchdog->endWatching();
}
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {
@@ -50,4 +57,4 @@ void CHyprWLListener::initCallback(wl_signal* pSignal, std::function<void(void*,
void CHyprWLListener::emit(void* data) {
m_pCallback(m_pOwner, data);
}
}

View File

@@ -27,15 +27,45 @@ wlr_surface* CWLSurface::wlr() const {
return m_pWLRSurface;
}
bool CWLSurface::small() const {
if (!m_pOwner || !exists())
return false;
return m_pOwner->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || m_pOwner->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1;
}
Vector2D CWLSurface::correctSmallVec() const {
if (!m_pOwner || !exists() || !small() || m_bFillIgnoreSmall)
return {};
const auto SIZE = getViewporterCorrectedSize();
return Vector2D{(m_pOwner->m_vReportedSize.x - SIZE.x) / 2, (m_pOwner->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) *
(m_pOwner->m_vRealSize.vec() / m_pOwner->m_vReportedSize);
}
Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists())
return {};
return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} :
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
}
void CWLSurface::destroy() {
if (!m_pWLRSurface)
return;
hyprListener_destroy.removeCallback();
m_pWLRSurface->data = nullptr;
m_pOwner = nullptr;
if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
g_pCompositor->m_pLastFocus = nullptr;
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
g_pInputManager->setCursorImageOverride("left_ptr");
m_pWLRSurface = nullptr;

View File

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

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

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

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

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

View File

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

View File

@@ -4,9 +4,9 @@
#include <string>
#include "../defines.hpp"
enum eFullscreenMode : uint8_t
{
FULLSCREEN_FULL = 0,
enum eFullscreenMode : int8_t {
FULLSCREEN_INVALID = -1,
FULLSCREEN_FULL = 0,
FULLSCREEN_MAXIMIZED
};
@@ -49,12 +49,12 @@ class CWorkspace {
bool m_bDefaultFloating = false;
bool m_bDefaultPseudo = false;
// don't destroy in sanity check
bool m_bIndestructible = false;
// last monitor (used on reconnect)
std::string m_szLastMonitor = "";
// Whether the user configured command for on-created-empty has been executed, if any
bool m_bOnCreatedEmptyExecuted = false;
void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on);

View File

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

View File

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

View File

@@ -47,7 +47,6 @@ extern "C" {
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_layer_shell_v1.h>
@@ -105,6 +104,8 @@ extern "C" {
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_tearing_control_v1.h>
#include <wlr/util/box.h>
#include <libdrm/drm_fourcc.h>
@@ -145,3 +146,5 @@ extern "C" {
#endif
#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) {
if (children[0]) {
const auto REVERSESPLITRATIO = 2.f - splitRatio;
static auto* const PSMARTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:smart_split")->intValue;
static auto* const PPRESERVESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:preserve_split")->intValue;
static auto* const PFLMULT = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
if (*PPRESERVESPLIT == 0 && *PSMARTSPLIT == 0) {
splitTop = size.y * *PFLMULT > size.x;
splitTop = box.h * *PFLMULT > box.w;
}
if (verticalOverride == true)
@@ -24,16 +21,14 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
if (SPLITSIDE) {
// split left/right
children[0]->position = position;
children[0]->size = Vector2D(size.x / 2.f * splitRatio, size.y);
children[1]->position = Vector2D(position.x + size.x / 2.f * splitRatio, position.y);
children[1]->size = Vector2D(size.x / 2.f * REVERSESPLITRATIO, size.y);
const float FIRSTSIZE = box.w / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h};
children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h};
} else {
// split top/bottom
children[0]->position = position;
children[0]->size = Vector2D(size.x, size.y / 2.f * splitRatio);
children[1]->position = Vector2D(position.x, position.y + size.y / 2.f * splitRatio);
children[1]->size = Vector2D(size.x, size.y / 2.f * REVERSESPLITRATIO);
const float FIRSTSIZE = box.h / 2.0 * splitRatio;
children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE};
children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE};
}
children[0]->recalcSizePosRecursive(force);
@@ -110,16 +105,19 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
}
// for gaps outer
const bool DISPLAYLEFT = STICKS(pNode->position.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool DISPLAYRIGHT = STICKS(pNode->position.x + pNode->size.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(pNode->position.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYBOTTOM = STICKS(pNode->position.y + pNode->size.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const bool DISPLAYLEFT = STICKS(pNode->box.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool DISPLAYRIGHT = STICKS(pNode->box.x + pNode->box.w, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(pNode->box.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYBOTTOM = STICKS(pNode->box.y + pNode->box.h, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
const auto PWINDOW = pNode->pWindow;
// get specific gaps and rules for this workspace,
// if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID));
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return;
PWINDOW->updateSpecialRenderData();
static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
@@ -135,8 +133,11 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
return;
}
PWINDOW->m_vSize = pNode->size;
PWINDOW->m_vPosition = pNode->position;
CBox nodeBox = pNode->box;
nodeBox.round();
PWINDOW->m_vSize = nodeBox.size();
PWINDOW->m_vPosition = nodeBox.pos();
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID);
@@ -157,6 +158,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
PWINDOW->updateWindowDecos();
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
return;
}
@@ -204,10 +207,13 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
// if special, we adjust the coords a bit
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue;
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
PWINDOW->m_vRealSize = calcSize * *PSCALEFACTOR;
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
wb.round(); // avoid rounding mess
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize * *PSCALEFACTOR);
PWINDOW->m_vRealPosition = wb.pos();
PWINDOW->m_vRealSize = wb.size();
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
} else {
PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos;
@@ -282,7 +288,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
}
// first, check if OPENINGON isn't too big.
const auto PREDSIZEMAX = OPENINGON ? Vector2D(OPENINGON->size.x, OPENINGON->size.y) : PMONITOR->vecSize;
const auto PREDSIZEMAX = OPENINGON ? Vector2D(OPENINGON->box.w, OPENINGON->box.h) : PMONITOR->vecSize;
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
@@ -291,13 +297,6 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
return;
}
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
}
// last fail-safe to avoid duplicate fullscreens
if ((!OPENINGON || OPENINGON->pWindow == pWindow) && getNodesOnWorkspace(PNODE->workspaceID) > 1) {
for (auto& node : m_lDwindleNodesData) {
@@ -310,8 +309,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
// if it's the first, it's easy. Make it fullscreen.
if (!OPENINGON || OPENINGON->pWindow == pWindow) {
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
PNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
PNODE->box = CBox{PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
applyNodeDataToWindow(PNODE);
@@ -320,39 +318,35 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
return;
}
// if it's a group, add the window
if (OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
&& !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
&& ((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));
if (!m_vOverrideFocalPoint && g_pInputManager->m_bWasDraggingWindow) {
for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS))
return;
break;
}
}
}
// if it's a group, add the window
if (OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow) && !m_vOverrideFocalPoint) { // we are not moving window
m_lDwindleNodesData.remove(*PNODE);
const wlr_box box = OPENINGON->pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents();
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);
}
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return;
}
@@ -362,8 +356,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto NEWPARENT = &m_lDwindleNodesData.back();
// make the parent have the OPENINGON's stats
NEWPARENT->position = OPENINGON->position;
NEWPARENT->size = OPENINGON->size;
NEWPARENT->box = OPENINGON->box;
NEWPARENT->workspaceID = OPENINGON->workspaceID;
NEWPARENT->pParent = OPENINGON->pParent;
NEWPARENT->isNode = true; // it is a node
@@ -372,7 +365,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto PWIDTHMULTIPLIER = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
// if cursor over first child, make it first, etc
const auto SIDEBYSIDE = NEWPARENT->size.x > NEWPARENT->size.y * *PWIDTHMULTIPLIER;
const auto SIDEBYSIDE = NEWPARENT->box.w > NEWPARENT->box.h * *PWIDTHMULTIPLIER;
NEWPARENT->splitTop = !SIDEBYSIDE;
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)
overrideDirection = DIRECTION_DEFAULT;
} else if (*PSMARTSPLIT == 1) {
const auto tl = NEWPARENT->position;
const auto tr = NEWPARENT->position + Vector2D(NEWPARENT->size.x, 0);
const auto bl = NEWPARENT->position + Vector2D(0, NEWPARENT->size.y);
const auto br = NEWPARENT->position + NEWPARENT->size;
const auto cc = NEWPARENT->position + NEWPARENT->size / 2;
const auto tl = NEWPARENT->box.pos();
const auto tr = NEWPARENT->box.pos() + Vector2D(NEWPARENT->box.w, 0);
const auto bl = NEWPARENT->box.pos() + Vector2D(0, NEWPARENT->box.h);
const auto br = NEWPARENT->box.pos() + NEWPARENT->box.size();
const auto cc = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
if (MOUSECOORDS.inTriangle(tl, tr, cc)) {
NEWPARENT->splitTop = true;
@@ -429,11 +422,9 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
}
} else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
if ((SIDEBYSIDE &&
VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / *PWIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x / 2.f,
NEWPARENT->position.y + NEWPARENT->size.y)) ||
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
(!SIDEBYSIDE &&
VECINRECT(MOUSECOORDS, NEWPARENT->position.x, NEWPARENT->position.y / *PWIDTHMULTIPLIER, NEWPARENT->position.x + NEWPARENT->size.x,
NEWPARENT->position.y + NEWPARENT->size.y / 2.f))) {
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
// we are hovering over the first node, make PNODE first.
NEWPARENT->children[1] = OPENINGON;
NEWPARENT->children[0] = PNODE;
@@ -462,18 +453,14 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
}
// Update the children
if (!verticalOverride && (NEWPARENT->size.x * *PWIDTHMULTIPLIER > NEWPARENT->size.y || horizontalOverride)) {
if (!verticalOverride && (NEWPARENT->box.w * *PWIDTHMULTIPLIER > NEWPARENT->box.h || horizontalOverride)) {
// split left/right -> forced
OPENINGON->position = NEWPARENT->position;
OPENINGON->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y);
PNODE->position = Vector2D(NEWPARENT->position.x + NEWPARENT->size.x / 2.f, NEWPARENT->position.y);
PNODE->size = Vector2D(NEWPARENT->size.x / 2.f, NEWPARENT->size.y);
OPENINGON->box = {NEWPARENT->box.pos(), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
PNODE->box = {Vector2D(NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y), Vector2D(NEWPARENT->box.w / 2.f, NEWPARENT->box.h)};
} else {
// split top/bottom
OPENINGON->position = NEWPARENT->position;
OPENINGON->size = Vector2D(NEWPARENT->size.x, NEWPARENT->size.y / 2.f);
PNODE->position = Vector2D(NEWPARENT->position.x, NEWPARENT->position.y + NEWPARENT->size.y / 2.f);
PNODE->size = Vector2D(NEWPARENT->size.x, NEWPARENT->size.y / 2.f);
OPENINGON->box = {NEWPARENT->box.pos(), Vector2D(NEWPARENT->box.w, NEWPARENT->box.h / 2.f)};
PNODE->box = {Vector2D(NEWPARENT->box.x, NEWPARENT->box.y + NEWPARENT->box.h / 2.f), Vector2D(NEWPARENT->box.w, NEWPARENT->box.h / 2.f)};
}
OPENINGON->pParent = NEWPARENT;
@@ -481,8 +468,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride);
applyNodeDataToWindow(PNODE);
applyNodeDataToWindow(OPENINGON);
recalculateMonitor(pWindow->m_iMonitorID);
pWindow->applyGroupRules();
}
@@ -510,9 +497,8 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
const auto PSIBLING = PPARENT->children[0] == PNODE ? PPARENT->children[1] : PPARENT->children[0];
PSIBLING->position = PPARENT->position;
PSIBLING->size = PPARENT->size;
PSIBLING->pParent = PPARENT->pParent;
PSIBLING->box = PPARENT->box;
PSIBLING->pParent = PPARENT->pParent;
if (PPARENT->pParent != nullptr) {
if (PPARENT->pParent->children[0] == PPARENT) {
@@ -551,8 +537,7 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->specialWorkspaceID);
if (TOPNODE && PMONITOR) {
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
TOPNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
TOPNODE->recalcSizePosRecursive();
}
}
@@ -567,11 +552,11 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
} else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
SDwindleNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
fakeNode.workspaceID = PWORKSPACE->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.position;
PFULLWINDOW->m_vSize = fakeNode.size;
PFULLWINDOW->m_vPosition = fakeNode.box.pos();
PFULLWINDOW->m_vSize = fakeNode.box.size();
fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode);
}
@@ -582,8 +567,7 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace);
if (TOPNODE && PMONITOR) {
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
TOPNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
TOPNODE->recalcSizePosRecursive();
}
}
@@ -628,7 +612,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
m_PseudoDragFlags.started = true;
const auto pseudoSize = PWINDOW->m_vRealSize.goalv();
const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->position + ((PNODE->size / 2) - (pseudoSize / 2)));
const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->box.pos() + ((PNODE->box.size() / 2) - (pseudoSize / 2)));
if (mouseOffset.x > 0 && mouseOffset.x < pseudoSize.x && mouseOffset.y > 0 && mouseOffset.y < pseudoSize.y) {
m_PseudoDragFlags.pseudo = true;
@@ -651,8 +635,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
else
PWINDOW->m_vPseudoSize.y -= pixResize.y * 2;
PWINDOW->m_vPseudoSize.x = std::clamp(PWINDOW->m_vPseudoSize.x, 30.0, PNODE->size.x);
PWINDOW->m_vPseudoSize.y = std::clamp(PWINDOW->m_vPseudoSize.y, 30.0, PNODE->size.y);
PWINDOW->m_vPseudoSize.x = std::clamp(PWINDOW->m_vPseudoSize.x, 30.0, PNODE->box.w);
PWINDOW->m_vPseudoSize.y = std::clamp(PWINDOW->m_vPseudoSize.y, 30.0, PNODE->box.h);
PWINDOW->m_vLastFloatingSize = PWINDOW->m_vPseudoSize;
PNODE->recalcSizePosRecursive(*PANIMATE == 0);
@@ -699,30 +683,30 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
}
if (PHOUTER) {
PHOUTER->pParent->splitRatio = std::clamp(PHOUTER->pParent->splitRatio + allowedMovement.x * 2.f / PHOUTER->pParent->size.x, 0.1, 1.9);
PHOUTER->pParent->splitRatio = std::clamp(PHOUTER->pParent->splitRatio + allowedMovement.x * 2.f / PHOUTER->pParent->box.w, 0.1, 1.9);
if (PHINNER) {
const auto ORIGINAL = PHINNER->size.x;
const auto ORIGINAL = PHINNER->box.w;
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
if (PHINNER->pParent->children[0] == PHINNER)
PHINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.x) / PHINNER->pParent->size.x * 2.f, 0.1, 1.9);
PHINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9);
else
PHINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.x) / PHINNER->pParent->size.x * 2.f, 0.1, 1.9);
PHINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.x) / PHINNER->pParent->box.w * 2.f, 0.1, 1.9);
PHINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
} else
PHOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
}
if (PVOUTER) {
PVOUTER->pParent->splitRatio = std::clamp(PVOUTER->pParent->splitRatio + allowedMovement.y * 2.f / PVOUTER->pParent->size.y, 0.1, 1.9);
PVOUTER->pParent->splitRatio = std::clamp(PVOUTER->pParent->splitRatio + allowedMovement.y * 2.f / PVOUTER->pParent->box.h, 0.1, 1.9);
if (PVINNER) {
const auto ORIGINAL = PVINNER->size.y;
const auto ORIGINAL = PVINNER->box.h;
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
if (PVINNER->pParent->children[0] == PVINNER)
PVINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.y) / PVINNER->pParent->size.y * 2.f, 0.1, 1.9);
PVINNER->pParent->splitRatio = std::clamp((ORIGINAL - allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9);
else
PVINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.y) / PVINNER->pParent->size.y * 2.f, 0.1, 1.9);
PVINNER->pParent->splitRatio = std::clamp(2 - (ORIGINAL + allowedMovement.y) / PVINNER->pParent->box.h * 2.f, 0.1, 1.9);
PVINNER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
} else
PVOUTER->pParent->recalcSizePosRecursive(*PANIMATE == 0);
@@ -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
if (!PPARENT2) {
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
allowedMovement.x *= 2.f / PPARENT->box.w;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
allowedMovement.y *= 2.f / PPARENT->box.h;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
}
@@ -761,11 +745,11 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
// no parent, one axis of freedom
if (!PPARENT2) {
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
allowedMovement.x *= 2.f / PPARENT->box.w;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
allowedMovement.y *= 2.f / PPARENT->box.h;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, 0.1, 1.9);
PPARENT->recalcSizePosRecursive(*PANIMATE == 0);
}
@@ -777,8 +761,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
const auto SIDECONTAINER = PARENTSIDEBYSIDE ? PPARENT : PPARENT2;
const auto TOPCONTAINER = PARENTSIDEBYSIDE ? PPARENT2 : PPARENT;
allowedMovement.x *= 2.f / SIDECONTAINER->size.x;
allowedMovement.y *= 2.f / TOPCONTAINER->size.y;
allowedMovement.x *= 2.f / SIDECONTAINER->box.w;
allowedMovement.y *= 2.f / TOPCONTAINER->box.h;
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, 0.1, 1.9);
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, 0.1, 1.9);
@@ -846,11 +830,10 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
SDwindleNodeData fakeNode;
fakeNode.pWindow = pWindow;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.position;
pWindow->m_vSize = fakeNode.size;
pWindow->m_vPosition = fakeNode.box.pos();
pWindow->m_vSize = fakeNode.box.size();
applyNodeDataToWindow(&fakeNode);
}
@@ -962,17 +945,15 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
}
if (ACTIVE1) {
ACTIVE1->position = PNODE->position;
ACTIVE1->size = PNODE->size;
ACTIVE1->pWindow->m_vPosition = ACTIVE1->position;
ACTIVE1->pWindow->m_vSize = ACTIVE1->size;
ACTIVE1->box = PNODE->box;
ACTIVE1->pWindow->m_vPosition = ACTIVE1->box.pos();
ACTIVE1->pWindow->m_vSize = ACTIVE1->box.size();
}
if (ACTIVE2) {
ACTIVE2->position = PNODE2->position;
ACTIVE2->size = PNODE2->size;
ACTIVE2->pWindow->m_vPosition = ACTIVE2->position;
ACTIVE2->pWindow->m_vSize = ACTIVE2->size;
ACTIVE2->box = PNODE2->box;
ACTIVE2->pWindow->m_vPosition = ACTIVE2->box.pos();
ACTIVE2->pWindow->m_vSize = ACTIVE2->box.size();
}
g_pHyprRenderer->damageWindow(pWindow);

View File

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

View File

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

View File

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

View File

@@ -94,45 +94,106 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
// if it's a group, add the window
if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
&& !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
&& ((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 (g_pInputManager->m_bWasDraggingWindow && OPENINGON) {
for (auto& wd : OPENINGON->pWindow->m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
if (!pWindow->m_sGroupData.pNextWindow)
pWindow->m_dWindowDecorations.emplace_back(std::make_unique<CHyprGroupBarDecoration>(pWindow));
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(MOUSECOORDS)) {
if (!wd->onEndWindowDragOnDeco(pWindow, MOUSECOORDS))
return;
break;
}
}
}
// if it's a group, add the window
if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow // target is group
&& pWindow->canBeGroupedInto(OPENINGON->pWindow)) {
m_lMasterNodesData.remove(*PNODE);
const wlr_box box = OPENINGON->pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents();
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);
}
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
pWindow->applyGroupRules();
pWindow->updateWindowDecos();
recalculateWindow(pWindow);
if (!pWindow->getDecorationByType(DECORATION_GROUPBAR))
pWindow->addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(pWindow));
return;
}
pWindow->applyGroupRules();
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) {
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
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
recalculateMonitor(pWindow->m_iMonitorID);
}
@@ -575,6 +629,9 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
// if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID));
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return;
PWINDOW->updateSpecialRenderData();
static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
@@ -611,6 +668,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->updateWindowDecos();
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
return;
}
@@ -633,15 +692,21 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue;
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
PWINDOW->m_vRealSize = calcSize * *PSCALEFACTOR;
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
wb.round(); // avoid rounding mess
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize * *PSCALEFACTOR);
PWINDOW->m_vRealPosition = wb.pos();
PWINDOW->m_vRealSize = wb.size();
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
} else {
PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos;
CBox wb = {calcPos, calcSize};
wb.round(); // avoid rounding mess
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
PWINDOW->m_vRealPosition = wb.pos();
PWINDOW->m_vRealSize = wb.size();
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
}
if (m_bForceWarps && !*PANIMATE) {
@@ -718,8 +783,9 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
default: UNREACHABLE();
}
const auto workspaceIdForResizing = PMONITOR->specialWorkspaceID == 0 ? PMONITOR->activeWorkspace : PMONITOR->specialWorkspaceID;
for (auto& n : m_lMasterNodesData) {
if (n.isMaster && n.workspaceID == PMONITOR->activeWorkspace)
if (n.isMaster && n.workspaceID == workspaceIdForResizing)
n.percMaster = std::clamp(n.percMaster + delta, 0.05, 0.95);
}
@@ -860,12 +926,13 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
// To keep consistent with the settings without C+P code
SMasterNodeData fakeNode;
fakeNode.pWindow = pWindow;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.position;
pWindow->m_vSize = fakeNode.size;
fakeNode.pWindow = pWindow;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.position;
pWindow->m_vSize = fakeNode.size;
fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode);
}
@@ -903,7 +970,16 @@ void CHyprMasterLayout::moveWindowTo(CWindow* pWindow, const std::string& dir) {
const auto PWINDOW2 = g_pCompositor->getWindowInDirection(pWindow, dir[0]);
switchWindows(pWindow, PWINDOW2);
if (pWindow->m_iWorkspaceID != PWINDOW2->m_iWorkspaceID) {
// if different monitors, send to monitor
onWindowRemovedTiling(pWindow);
pWindow->moveToWorkspace(PWINDOW2->m_iWorkspaceID);
pWindow->m_iMonitorID = PWINDOW2->m_iMonitorID;
onWindowCreatedTiling(pWindow);
} else {
// if same monitor, switch windows
switchWindows(pWindow, PWINDOW2);
}
}
void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {

View File

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

View File

@@ -14,22 +14,7 @@
#define ISDEBUG false
#endif
// git stuff
#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
#include "version.h"
#define SPECIAL_WORKSPACE_START (-99)
@@ -57,7 +42,7 @@
if (!(expr)) { \
Debug::log(CRIT, "\n==========================================================================================\nASSERTION FAILED! \n\n{}\n\nat: line {} in {}", \
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."); \
raise(SIGABRT); \
}
@@ -76,7 +61,9 @@
}
#define FORMAT_FLAG(spec__, flag__) \
case spec__: (flag__) = true; break;
case spec__: \
(flag__) = true; \
break;
#define FORMAT_NUMBER(buf__) \
case '0': \
@@ -88,7 +75,9 @@
case '6': \
case '7': \
case '8': \
case '9': (buf__).push_back(*it); break;
case '9': \
(buf__).push_back(*it); \
break;
#if ISDEBUG
#define UNREACHABLE() \

View File

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

View File

@@ -68,6 +68,7 @@ void CAnimationManager::tick() {
if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) {
av->warp(false);
animationEndedVars.push_back(av);
continue;
}
@@ -81,7 +82,7 @@ void CAnimationManager::tick() {
CMonitor* PMONITOR = nullptr;
bool animationsDisabled = animGlobalDisabled;
wlr_box WLRBOXPREV = {0, 0, 0, 0};
CBox WLRBOXPREV = {0, 0, 0, 0};
if (PWINDOW) {
WLRBOXPREV = PWINDOW->getFullWindowBoundingBox();
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
@@ -93,6 +94,12 @@ void CAnimationManager::tick() {
if (!PMONITOR)
continue;
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) {
WLRBOXPREV = PLAYER->geometry;
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
// 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, BORDERSIZE + ROUNDINGSIZE, WLRBOXNEW.height + 2 * BORDERSIZE); // left
g_pHyprRenderer->damageBox(WLRBOXNEW.x + WLRBOXNEW.width - ROUNDINGSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE,
@@ -242,29 +249,9 @@ void CAnimationManager::tick() {
case AVARDAMAGE_SHADOW: {
RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!");
static auto* const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW);
const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW);
if (PDECO) {
const auto EXTENTS = PDECO->getWindowDecorationExtents();
wlr_box dmg = {PWINDOW->m_vRealPosition.vec().x - EXTENTS.topLeft.x, PWINDOW->m_vRealPosition.vec().y - EXTENTS.topLeft.y,
PWINDOW->m_vRealSize.vec().x + EXTENTS.topLeft.x + EXTENTS.bottomRight.x,
PWINDOW->m_vRealSize.vec().y + EXTENTS.topLeft.y + EXTENTS.bottomRight.y};
if (!*PSHADOWIGNOREWINDOW) {
// easy, damage the entire box
g_pHyprRenderer->damageBox(&dmg);
} else {
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);
}
}
PDECO->damageEntire();
break;
}
@@ -423,7 +410,7 @@ void CAnimationManager::onWindowPostCreateClose(CWindow* pWindow, bool close) {
if (pWindow->m_sAdditionalConfigData.animationStyle != "") {
// 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(' ')) {
// has a direction
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
float minPerc = 0.f;
if (ANIMSTYLE.find("%") != 0) {
if (!ANIMSTYLE.starts_with("%")) {
try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' '));
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) {
if (config.find("window") == 0) {
if (config.starts_with("window")) {
if (style == "slide") {
return "";
} else if (style.find("popin") == 0) {
} else if (style.starts_with("popin")) {
// try parsing
float minPerc = 0.f;
if (style.find("%") != std::string::npos) {
@@ -491,7 +478,7 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config,
} else if (config == "workspaces" || config == "specialWorkspace") {
if (style == "slide" || style == "slidevert" || style == "fade")
return "";
else if (style.find("slidefade") == 0) {
else if (style.starts_with("slidefade")) {
// try parsing
float movePerc = 0.f;
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())
return;
@@ -38,7 +38,7 @@ void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, std:
if (!cb.handle) {
// we don't guard hl hooks
(*cb.fn)(cb.fn, data);
(*cb.fn)(cb.fn, info, data);
continue;
}
@@ -49,7 +49,7 @@ void CHookSystemManager::emit(const std::vector<SCallbackFNPtr>* callbacks, std:
try {
if (!setjmp(m_jbHookFaultJumpBuf))
(*cb.fn)(cb.fn, data);
(*cb.fn)(cb.fn, info, data);
else {
// this module crashed.
throw std::exception();

View File

@@ -12,7 +12,8 @@
#include "../plugins/PluginAPI.hpp"
// 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 {
HOOK_CALLBACK_FN* fn = nullptr;
@@ -22,7 +23,17 @@ struct SCallbackFNPtr {
#define EMIT_HOOK_EVENT(name, param) \
{ \
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 {
@@ -34,7 +45,7 @@ class CHookSystemManager {
void hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn, HANDLE handle = nullptr);
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);
bool m_bCurrentEventPlugin = false;

View File

@@ -1,5 +1,7 @@
#include "KeybindManager.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "debug/Log.hpp"
#include "helpers/VarList.hpp"
#include <regex>
@@ -77,7 +79,7 @@ CKeybindManager::CKeybindManager() {
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
m_pActiveKeybind = nullptr;
m_vPressedSpecialBinds.clear();
@@ -435,7 +437,8 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
const bool IGNORECONDITIONS =
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;
if (!key.empty()) {
@@ -804,12 +807,13 @@ void CKeybindManager::changeworkspace(std::string args) {
// 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 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 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.
if (PCURRENTWORKSPACE->m_sPrevWorkspace.iID == -1) {
Debug::log(LOG, "No previous workspace to change to");
@@ -863,9 +867,13 @@ void CKeybindManager::changeworkspace(std::string args) {
PMONITORWORKSPACEOWNER->changeWorkspace(pWorkspaceToChangeTo, false, true);
if (PMONITOR != PMONITORWORKSPACEOWNER) {
g_pCompositor->warpCursorTo(PMONITORWORKSPACEOWNER->middle());
if (const auto PLAST = pWorkspaceToChangeTo->getLastFocusedWindow(); PLAST)
Vector2D middle = PMONITORWORKSPACEOWNER->middle();
if (const auto PLAST = pWorkspaceToChangeTo->getLastFocusedWindow(); PLAST) {
g_pCompositor->focusWindow(PLAST);
if (*PWORKSPACECENTERON == 1)
middle = PLAST->middle();
}
g_pCompositor->warpCursorTo(middle);
}
if (BISWORKSPACECURRENT) {
@@ -996,7 +1004,8 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
}
void CKeybindManager::moveFocusTo(std::string args) {
char arg = args[0];
static auto* const PFULLCYCLE = &g_pConfigManager->getConfigValuePtr("binds:movefocus_cycles_fullscreen")->intValue;
char arg = args[0];
if (!isDirection(args)) {
Debug::log(ERR, "Cannot move focus in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg);
@@ -1012,7 +1021,7 @@ void CKeybindManager::moveFocusTo(std::string args) {
// remove constraints
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)) :
g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
@@ -1083,13 +1092,13 @@ void CKeybindManager::swapActive(std::string args) {
return;
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) {
char arg = args[0];
if (args.find("mon:") == 0) {
if (args.starts_with("mon:")) {
const auto PNEWMONITOR = g_pCompositor->getMonitorFromString(args.substr(4));
if (!PNEWMONITOR)
return;
@@ -1109,20 +1118,20 @@ void CKeybindManager::moveActiveTo(std::string args) {
return;
if (PLASTWINDOW->m_bIsFloating) {
auto vPos = PLASTWINDOW->m_vRealPosition.goalv();
Vector2D vPos;
const auto PMONITOR = g_pCompositor->getMonitorFromID(PLASTWINDOW->m_iMonitorID);
const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize();
switch (arg) {
case 'l': vPos.x = PMONITOR->vecReservedTopLeft.x + BORDERSIZE; break;
case 'r': vPos.x = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize.goalv().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 + PMONITOR->vecPosition.x; break;
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 '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;
}
@@ -1172,6 +1181,18 @@ void CKeybindManager::changeGroupActive(std::string args) {
if (PWINDOW->m_sGroupData.pNextWindow == PWINDOW)
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") {
PWINDOW->setGroupCurrent(PWINDOW->m_sGroupData.pNextWindow);
} else {
@@ -1204,7 +1225,7 @@ void CKeybindManager::alterSplitRatio(std::string args) {
}
if (splitratio == 0) {
if (args.find("exact") == 0) {
if (args.starts_with("exact")) {
exact = true;
splitratio = getPlusMinusKeywordResult(args.substr(5), 0);
} else {
@@ -1704,10 +1725,10 @@ void CKeybindManager::toggleOpaque(std::string unused) {
}
void CKeybindManager::dpms(std::string arg) {
bool enable = arg.find("on") == 0;
bool enable = arg.starts_with("on");
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
if (arg.find_first_of(' ') != std::string::npos)
@@ -1819,25 +1840,22 @@ void CKeybindManager::mouse(std::string args) {
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(mouseCoords) && pWindow->m_sGroupData.pNextWindow) {
const wlr_box box = pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents();
if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) {
const int SIZE = pWindow->getGroupSize();
pWindow = pWindow->getGroupWindowByIndex((mouseCoords.x - box.x) * SIZE / box.width);
if (pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(mouseCoords)) {
for (auto& wd : pWindow->m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
// hack
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow);
if (!pWindow->m_bIsFloating) {
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked;
g_pKeybindManager->m_bGroupsLocked = true;
g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow);
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) {
wd->onBeginWindowDragOnDeco(mouseCoords);
break;
}
}
}
g_pInputManager->currentlyDraggedWindow = pWindow;
g_pInputManager->dragMode = MBIND_MOVE;
if (!g_pInputManager->currentlyDraggedWindow)
g_pInputManager->currentlyDraggedWindow = pWindow;
g_pInputManager->dragMode = MBIND_MOVE;
g_pLayoutManager->getCurrentLayout()->onBeginDragWindow();
} else {
g_pKeybindManager->m_bIsMouseBindActive = false;
@@ -1946,12 +1964,9 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi
if (pWindow->m_sGroupData.deny)
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!
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->insertWindowToGroup(pWindow);
@@ -1960,11 +1975,13 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi
g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow);
g_pCompositor->focusWindow(pWindow);
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) {
static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("misc:group_focus_removed_window")->intValue;
static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("group:focus_removed_window")->intValue;
const auto PWINDOWPREV = pWindow->getGroupPrevious();
eDirection direction;
@@ -2003,7 +2020,10 @@ void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string&
void CKeybindManager::moveIntoGroup(std::string args) {
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)) {
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;
// 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;
moveWindowIntoGroup(PWINDOW, PWINDOWINDIR);
}
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;
if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow)
@@ -2049,6 +2074,12 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
const auto PWINDOW = g_pCompositor->m_pLastWindow;
if (!PWINDOW || PWINDOW->m_bIsFullscreen)
return;
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) {
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
return;
}
const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg);
const bool ISWINDOWGROUP = PWINDOW->m_sGroupData.pNextWindow;

View File

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

View File

@@ -74,7 +74,7 @@ void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) {
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) {
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->height = pWindow->m_uSurface.xwayland->height;
}
} else
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, pbox);
} else {
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, pbox->pWlr());
pbox->applyFromWlr();
}
}
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
}
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;
pWindow->m_vReportedPosition = windowPos;
pWindow->m_vReportedSize = size;
pWindow->m_vReportedPosition = windowPos;
pWindow->m_vPendingReportedSize = size;
pWindow->m_fX11SurfaceScaledBy = 1.f;
@@ -178,12 +180,15 @@ void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, Vector2D size, bool f
if (pWindow->m_bIsX11)
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, windowPos.x, windowPos.y, size.x, size.y);
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) {
if (!pWindow->m_bIsX11)
wlr_xdg_toplevel_set_tiled(pWindow->m_uSurface.xdg->toplevel, edgez);
if (pWindow->m_bIsX11)
return;
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) {

View File

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

View File

@@ -41,8 +41,6 @@ void CInputManager::simulateMouseMovement() {
clock_gettime(CLOCK_MONOTONIC, &now);
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);
m_tmrLastCursorMovement.reset();
}
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 PMOUSEDPMS = &g_pConfigManager->getConfigValuePtr("misc:mouse_move_enables_dpms")->intValue;
static auto* const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
static auto* const PHOGFOCUS = &g_pConfigManager->getConfigValuePtr("misc:layers_hog_keyboard_focus")->intValue;
static auto* const PFLOATBEHAVIOR = &g_pConfigManager->getConfigValuePtr("input:float_switch_override_focus")->intValue;
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 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 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;
@@ -102,11 +96,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored && !refocus)
return;
EMIT_HOOK_EVENT_CANCELLABLE("mouseMove", MOUSECOORDSFLOORED);
if (time)
g_pCompositor->notifyIdleActivity();
EMIT_HOOK_EVENT("mouseMove", MOUSECOORDSFLOORED);
m_vLastCursorPosFloored = MOUSECOORDSFLOORED;
const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
@@ -118,7 +112,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (*PZOOMFACTOR != 1.f)
g_pHyprRenderer->damageMonitor(PMONITOR);
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
if (!PMONITOR->solitaryClient && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0)
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
CWindow* forcedFocus = m_pForcedFocus;
@@ -187,9 +182,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// update stuff
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) {
foundSurface = g_pCompositor->m_pLastFocus;
foundSurface = m_pLastMouseSurface;
pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface);
if (pFoundLayerSurface) {
surfacePos = g_pCompositor->getLayerSurfaceFromSurface(foundSurface)->position;
@@ -201,10 +196,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
pFoundLayerSurface = nullptr;
}
} else if (g_pCompositor->m_pLastWindow) {
foundSurface = g_pCompositor->m_pLastFocus;
foundSurface = m_pLastMouseSurface;
pFoundWindow = g_pCompositor->m_pLastWindow;
surfacePos = g_pCompositor->m_pLastWindow->m_vRealPosition.vec();
surfaceCoords = g_pCompositor->vectorToSurfaceLocal(mouseCoords, pFoundWindow, foundSurface);
m_bFocusHeldByButtons = true;
m_bRefocusHeldByButtons = refocus;
@@ -306,19 +301,19 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (g_pHyprRenderer->m_bHasARenderedCursor) {
// TODO: maybe wrap?
if (m_ecbClickBehavior == CLICKMODE_KILL)
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "crosshair");
setCursorImageOverride("crosshair");
else
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "left_ptr");
setCursorImageOverride("left_ptr");
}
m_bEmptyFocusCursorSet = true;
}
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);
}
return;
}
@@ -340,12 +335,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
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);
if (PLS && PLS->layerSurface->current.keyboard_interactive) {
if (PLS && PLS->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
allowKeyboardRefocus = false;
}
}
// set the values for use
@@ -361,6 +355,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
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) {
// change cursor icon if hovering over border
if (*PRESIZEONBORDER && *PRESIZECURSORICON) {
@@ -371,34 +373,22 @@ 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 (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow &&
((pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR == 2) || (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR != 0))) {
// enter if change floating style
if (FOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
m_pLastMouseSurface = foundSurface;
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} else if (FOLLOWMOUSE == 2 || FOLLOWMOUSE == 3) {
m_pLastMouseSurface = foundSurface;
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
if (pFoundWindow == g_pCompositor->m_pLastWindow) {
if (foundSurface != g_pCompositor->m_pLastFocus || m_bLastFocusOnLS) {
// ^^^ changed the subsurface ^^^ came back from a LS
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
m_pLastMouseSurface = foundSurface;
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
if (FOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow)
@@ -421,7 +411,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
}
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) {
g_pCompositor->focusSurface(foundSurface);
}
@@ -430,14 +421,15 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
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_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
}
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();
@@ -473,32 +465,72 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
else
g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
if (!cursorImageUnlocked() || !g_pHyprRenderer->shouldRenderCursor())
if (!cursorImageUnlocked() || !g_pHyprRenderer->m_bHasARenderedCursor)
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) {
// hyprListener_CursorSurfaceDestroy.removeCallback();
// hyprListener_CursorSurfaceDestroy.initCallback(
// &e->surface->events.destroy, [&](void* owner, void* data) { cursorSurfaceInfo.pSurface = nullptr; }, this, "InputManager");
// cursorSurfaceInfo.vHotspot = {e->hotspot_x, e->hotspot_y};
// }
if (e->surface) {
m_sCursorSurfaceInfo.wlSurface.assign(e->surface);
m_sCursorSurfaceInfo.vHotspot = {e->hotspot_x, e->hotspot_y};
m_sCursorSurfaceInfo.hidden = false;
} else {
m_sCursorSurfaceInfo.vHotspot = {};
m_sCursorSurfaceInfo.hidden = true;
}
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client)
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, e->surface, e->hotspot_x, e->hotspot_y);
m_sCursorSurfaceInfo.name = "";
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) {
if (!g_pHyprRenderer->shouldRenderCursor() || !cursorImageUnlocked())
if (!g_pHyprRenderer->m_bHasARenderedCursor || !cursorImageUnlocked())
return;
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));
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
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() {
if (!g_pHyprRenderer->shouldRenderCursor())
if (!g_pHyprRenderer->m_bHasARenderedCursor)
return false;
if (m_ecbClickBehavior == CLICKMODE_KILL)
@@ -519,7 +551,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
case CLICKMODE_DEFAULT:
Debug::log(LOG, "SetClickMode: 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;
case CLICKMODE_KILL:
@@ -531,7 +563,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
refocus();
// set cursor
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "crosshair");
g_pHyprRenderer->setCursorFromName("crosshair");
break;
default: break;
}
@@ -551,16 +583,15 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
const auto w = g_pCompositor->vectorToWindowIdeal(mouseCoords);
if (w && !w->m_bIsFullscreen && !w->hasPopupAt(mouseCoords) && w->m_sGroupData.pNextWindow) {
const wlr_box box = w->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents();
if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) {
if (e->state == WLR_BUTTON_PRESSED) {
const int SIZE = w->getGroupSize();
CWindow* pWindow = w->getGroupWindowByIndex((mouseCoords.x - box.x) * SIZE / box.width);
if (w != pWindow)
w->setGroupCurrent(pWindow);
if (w && !w->m_bIsFullscreen && !w->hasPopupAt(mouseCoords)) {
for (auto& wd : w->m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
if (g_pDecorationPositioner->getWindowDecorationBox(wd.get()).containsPoint(mouseCoords)) {
wd->onMouseButtonOnDeco(mouseCoords, e);
return;
}
return;
}
}
@@ -568,8 +599,8 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
// TODO detect click on LS properly
if (*PRESIZEONBORDER && !m_bLastFocusOnLS) {
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};
if ((!wlr_box_contains_point(&real, mouseCoords.x, mouseCoords.y) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) && !w->hasPopupAt(mouseCoords)) {
const CBox real = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if ((!real.containsPoint(mouseCoords) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) && !w->hasPopupAt(mouseCoords)) {
g_pKeybindManager->resizeWithBorder(e);
return;
}
@@ -581,7 +612,8 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
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
// if we only pressed one button, allow us to refocus. m_lCurrentlyHeldButtons.size() > 0 will stick the focus
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) {
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);
@@ -643,8 +675,8 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
const auto pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS);
if (*PGROUPBARSCROLLING && pWindow && !pWindow->m_bIsFullscreen && !pWindow->hasPopupAt(MOUSECOORDS) && pWindow->m_sGroupData.pNextWindow) {
const wlr_box box = pWindow->getDecorationByType(DECORATION_GROUPBAR)->getWindowDecorationRegion().getExtents();
if (wlr_box_contains_point(&box, MOUSECOORDS.x, MOUSECOORDS.y)) {
const CBox box = g_pDecorationPositioner->getWindowDecorationBox(pWindow->getDecorationByType(DECORATION_GROUPBAR));
if (box.containsPoint(MOUSECOORDS)) {
if (e->delta > 0)
pWindow->setGroupCurrent(pWindow->m_sGroupData.pNextWindow);
else
@@ -1011,7 +1043,7 @@ void CInputManager::setPointerConfigs() {
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE);
} else if (ACCELPROFILE == "flat") {
libinput_device_config_accel_set_profile(LIBINPUTDEV, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT);
} else if (ACCELPROFILE.find("custom") == 0) {
} else if (ACCELPROFILE.starts_with("custom")) {
CVarList args = {ACCELPROFILE, 0, ' '};
try {
double step = std::stod(args[1]);
@@ -1175,7 +1207,7 @@ void CInputManager::updateDragIcon() {
switch (m_sDrag.dragIcon->drag->grab_type) {
case WLR_DRAG_GRAB_KEYBOARD: break;
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);
m_sDrag.pos = getMouseCoordsInternal();
break;
@@ -1202,24 +1234,30 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
return;
const auto MOUSECOORDS = getMouseCoordsInternal();
const auto PCONSTRAINT = constraintFromWlr(constraint);
pMouse->hyprListener_commitConstraint.removeCallback();
if (pMouse->currentConstraint) {
if (constraint) {
const auto PCONSTRAINT = constraintFromWlr(constraint);
if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) {
PCONSTRAINT->hintSet = true;
PCONSTRAINT->positionHint = {constraint->current.cursor_hint.x, constraint->current.cursor_hint.y};
}
if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT && constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
warpMouseToConstraintMiddle(PCONSTRAINT);
}
if (pMouse->currentConstraint)
wlr_pointer_constraint_v1_send_deactivated(pMouse->currentConstraint);
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) {
PCONSTRAINT->hintSet = true;
PCONSTRAINT->positionHint = {constraint->current.cursor_hint.x, constraint->current.cursor_hint.y};
}
if (constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT && constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
warpMouseToConstraintMiddle(PCONSTRAINT);
pMouse->currentConstraint = constraint;
pMouse->constraintActive = true;
@@ -1231,7 +1269,7 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
// warp to the constraint
recheckConstraint(pMouse);
constraintFromWlr(constraint)->active = true;
PCONSTRAINT->active = true;
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);
if (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();
const auto RELATIVETO = pConstraint->getLogicConstraintPos();
const auto HINTSCALE = PWINDOW->m_fX11SurfaceScaledBy;
if (pConstraint->hintSet) {
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();
auto HINT = pConstraint->hintSet ? pConstraint->positionHint : pConstraint->cursorPosOnActivate;
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, RELATIVETO.x + RELATIVESIZE.x / 2.f, RELATIVETO.y + RELATIVESIZE.y / 2.f);
wlr_seat_pointer_warp(pConstraint->constraint->seat, RELATIVESIZE.x / 2.f, RELATIVESIZE.y / 2.f);
if (HINT == Vector2D{-1, -1})
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_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) {
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, name.c_str());
m_bCursorImageOverridden = true;
g_pHyprRenderer->setCursorFromName(name.c_str());
m_bCursorImageOverridden = true;
m_sCursorSurfaceInfo.inUse = false;
}
void CInputManager::unsetCursorImage() {
@@ -1504,8 +1543,7 @@ void CInputManager::unsetCursorImage() {
return;
m_bCursorImageOverridden = false;
if (!g_pHyprRenderer->m_bWindowRequestedCursorHide)
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, "left_ptr");
restoreCursorIconToApp();
}
std::string CInputManager::deviceNameToInternalString(std::string in) {
@@ -1583,49 +1621,70 @@ void CInputManager::setCursorIconOnBorder(CWindow* w) {
// give a small leeway (10 px) for corner icon
const auto CORNER = *PROUNDING + BORDERSIZE + 10;
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;
wlr_box boxFullGrabInput = {box.x - *PEXTENDBORDERGRAB - BORDERSIZE, box.y - *PEXTENDBORDERGRAB - BORDERSIZE, box.width + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE),
box.height + 2 * (*PEXTENDBORDERGRAB + BORDERSIZE)};
CBox boxFullGrabInput = {box.x - *PEXTENDBORDERGRAB - BORDERSIZE, box.y - *PEXTENDBORDERGRAB - BORDERSIZE, box.width + 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;
} else if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) {
if (!w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) {
direction = BORDERICON_NONE;
} else {
if (mouseCoords.y < box.y + CORNER) {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_UP_LEFT;
else
direction = BORDERICON_UP_RIGHT;
} else {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_DOWN_LEFT;
else
direction = BORDERICON_DOWN_RIGHT;
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;
}
}
} else {
if (mouseCoords.y < box.y + CORNER) {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_UP_LEFT;
else if (mouseCoords.x > box.x + box.width - CORNER)
direction = BORDERICON_UP_RIGHT;
else
direction = BORDERICON_UP;
} else if (mouseCoords.y > box.y + box.height - CORNER) {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_DOWN_LEFT;
else if (mouseCoords.x > box.x + box.width - CORNER)
direction = BORDERICON_DOWN_RIGHT;
else
direction = BORDERICON_DOWN;
} else {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_LEFT;
else if (mouseCoords.x > box.x + box.width - CORNER)
direction = BORDERICON_RIGHT;
if (onDeco)
direction = BORDERICON_NONE;
else {
if (box.containsPoint(mouseCoords)) {
if (!w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) {
direction = BORDERICON_NONE;
} else {
if (mouseCoords.y < box.y + CORNER) {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_UP_LEFT;
else
direction = BORDERICON_UP_RIGHT;
} else {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_DOWN_LEFT;
else
direction = BORDERICON_DOWN_RIGHT;
}
}
} else {
if (mouseCoords.y < box.y + CORNER) {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_UP_LEFT;
else if (mouseCoords.x > box.x + box.width - CORNER)
direction = BORDERICON_UP_RIGHT;
else
direction = BORDERICON_UP;
} else if (mouseCoords.y > box.y + box.height - CORNER) {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_DOWN_LEFT;
else if (mouseCoords.x > box.x + box.width - CORNER)
direction = BORDERICON_DOWN_RIGHT;
else
direction = BORDERICON_DOWN;
} else {
if (mouseCoords.x < box.x + CORNER)
direction = BORDERICON_LEFT;
else if (mouseCoords.x > box.x + box.width - CORNER)
direction = BORDERICON_RIGHT;
}
}
}
}

View File

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

View File

@@ -3,7 +3,7 @@
#include "../../Compositor.hpp"
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) {
@@ -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;
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;
Vector2D parentPos;
@@ -209,7 +209,7 @@ void CInputMethodRelay::updateInputPopup(SIMEPopup* pPopup) {
if (!pMonitor)
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)
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);
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);
}

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 PSWIPEUSER = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_use_r")->intValue;
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
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;
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);

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) {
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
const auto LOCAL = CURSORPOS - PWINDOW->m_vRealPosition.goalv();
if (PTOOL->pSurface != g_pCompositor->m_pLastFocus)
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);
}
if (motion)
wlr_tablet_v2_tablet_tool_notify_motion(PTOOL->wlrTabletToolV2, LOCAL.x, LOCAL.y);
if (motion) {
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 {
if (PTOOL->pSurface)
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->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 {
g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), m_sTouchData.touchFocusWindow, local);
m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local;
}
m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local;
} else if (m_sTouchData.touchFocusLS) {
local = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_sTouchData.touchFocusLS->geometry.x, m_sTouchData.touchFocusLS->geometry.y);
@@ -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);
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_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')
executable('Hyprland', src,

View File

@@ -9,6 +9,10 @@
#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) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
@@ -107,7 +111,7 @@ APICALL bool HyprlandAPI::removeFunctionHook(HANDLE handle, CFunctionHook* 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);
if (!PLUGIN)
@@ -116,11 +120,10 @@ APICALL bool HyprlandAPI::addWindowDecoration(HANDLE handle, CWindow* pWindow, I
if (!g_pCompositor->windowValidMapped(pWindow))
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);
return true;
@@ -135,7 +138,7 @@ APICALL bool HyprlandAPI::removeWindowDecoration(HANDLE handle, IHyprWindowDecor
for (auto& w : g_pCompositor->m_vWindows) {
for (auto& d : w->m_dWindowDecorations) {
if (d.get() == pDecoration) {
std::erase(w->m_dWindowDecorations, d);
w->removeWindowDeco(pDecoration);
return true;
}
}
@@ -153,13 +156,26 @@ APICALL bool HyprlandAPI::addConfigValue(HANDLE handle, const std::string& name,
if (!PLUGIN)
return false;
if (name.find("plugin:") != 0)
if (!name.starts_with("plugin:"))
return false;
g_pConfigManager->addPluginConfigVar(handle, name, value);
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) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
@@ -277,7 +293,7 @@ APICALL std::vector<SFunctionMatch> HyprlandAPI::findFunctionsByName(HANDLE hand
const auto FPATH = std::filesystem::canonical(exe);
#elif defined(__OpenBSD__)
// Neither KERN_PROC_PATHNAME nor /proc are supported
const auto FPATH = std::filesystem::canonical("/usr/local/bin/Hyprland");
const auto FPATH = std::filesystem::canonical("/usr/local/bin/Hyprland");
#else
const auto FPATH = std::filesystem::canonical("/proc/self/exe");
#endif
@@ -301,7 +317,11 @@ APICALL std::vector<SFunctionMatch> HyprlandAPI::findFunctionsByName(HANDLE hand
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()) {
@@ -334,3 +354,12 @@ APICALL std::vector<SFunctionMatch> HyprlandAPI::findFunctionsByName(HANDLE hand
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 "HookSystem.hpp"
#include "../SharedDefs.hpp"
#include "../version.h"
#include <any>
#include <functional>
#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 {
std::string name;
std::string description;
@@ -42,6 +43,14 @@ struct SFunctionMatch {
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 EXPORT __attribute__((visibility("default")))
#define REQUIRED
@@ -105,6 +114,14 @@ namespace HyprlandAPI {
*/
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.
@@ -204,7 +221,7 @@ namespace HyprlandAPI {
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
@@ -250,4 +267,24 @@ namespace HyprlandAPI {
Empty means either none found or handle was invalid
*/
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 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);
wl_resource_set_implementation(PADDON->pResource, &fractionalScaleAddonImpl, PADDON, handleAddonDestroy);

View File

@@ -119,7 +119,7 @@ CScreencopyClient::~CScreencopyClient() {
CScreencopyClient::CScreencopyClient() {
lastMeasure.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() {
@@ -183,7 +183,7 @@ void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force
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 PFRAME = &m_lFrames.emplace_back();
@@ -239,8 +239,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
}
int ow, oh;
wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh);
wlr_box_transform(&PFRAME->box, &PFRAME->box, PFRAME->pMonitor->transform, ow, oh);
scaleBox(&PFRAME->box, PFRAME->pMonitor->scale);
PFRAME->box.transform(PFRAME->pMonitor->transform, ow, oh).scale(PFRAME->pMonitor->scale).round();
PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width;
@@ -263,20 +262,23 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
return;
}
const auto PBUFFER = wlr_buffer_from_resource(buffer);
const auto PBUFFER = wlr_buffer_try_from_resource(buffer);
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");
removeFrame(PFRAME);
return;
}
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");
removeFrame(PFRAME);
return;
}
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");
removeFrame(PFRAME);
return;
@@ -290,6 +292,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF;
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");
removeFrame(PFRAME);
return;
@@ -298,15 +301,18 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
wlr_buffer_end_data_ptr_access(PBUFFER);
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");
removeFrame(PFRAME);
return;
} 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");
removeFrame(PFRAME);
return;
}
} 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");
removeFrame(PFRAME);
return;
@@ -325,7 +331,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
}
void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) {
m_pLastMonitorBackBuffer = e->buffer;
m_pLastMonitorBackBuffer = e->state->buffer;
shareAllFrames(pMonitor);
m_pLastMonitorBackBuffer = nullptr;
}
@@ -382,11 +388,13 @@ void CScreencopyProtocolManager::shareFrame(SScreencopyFrame* frame) {
uint32_t flags = 0;
if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
if (!copyFrameDmabuf(frame)) {
Debug::log(ERR, "[sc] dmabuf copy failed in {:x}", (uintptr_t)frame);
zwlr_screencopy_frame_v1_send_failed(frame->resource);
return;
}
} else {
if (!copyFrameShm(frame, &now)) {
Debug::log(ERR, "[sc] shm copy failed in {:x}", (uintptr_t)frame);
zwlr_screencopy_frame_v1_send_failed(frame->resource);
return;
}

View File

@@ -46,7 +46,7 @@ struct SScreencopyFrame {
uint32_t shmFormat = 0;
uint32_t dmabufFormat = 0;
wlr_box box = {0};
CBox box = {};
int shmStride = 0;
bool overlayCursor = false;
@@ -73,7 +73,7 @@ class CScreencopyProtocolManager {
void removeFrame(SScreencopyFrame* frame, bool force = false);
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);

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) {
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) {

View File

@@ -39,9 +39,9 @@ struct STextInputV1 {
uint32_t purpose = 0;
} 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;
}
};

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)};
int 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;
@@ -229,7 +229,7 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r
return;
}
const auto PBUFFER = wlr_buffer_from_resource(buffer);
const auto PBUFFER = wlr_buffer_try_from_resource(buffer);
if (!PBUFFER) {
wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
removeFrame(PFRAME);
@@ -301,9 +301,9 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp
if (PMONITOR != g_pCompositor->getMonitorFromID(f->pWindow->m_iMonitorID))
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;
shareFrame(f);
@@ -448,7 +448,7 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti
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->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) {
g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, std::any param) { this->updateAllOutputs(); });
g_pHookSystem->hookDynamic("configReloaded", [this](void* self, std::any param) { this->updateAllOutputs(); });
g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, std::any param) {
g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, 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, SCallbackInfo& info, std::any param) {
const auto PMONITOR = std::any_cast<CMonitor*>(param);
std::erase_if(m_vXDGOutputs, [&](const auto& other) {
const auto REMOVE = other->monitor == PMONITOR;
@@ -72,15 +72,9 @@ CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver
}
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);
if (!PMONITOR)
return;
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(OUTPUT);
SXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique<SXDGOutput>(PMONITOR)).get();
#ifndef NO_XWAYLAND
@@ -99,6 +93,10 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(wl_client* client, wl_resource* r
pXDGOutput->resource->setImplementation(&OUTPUT_IMPL, nullptr);
pXDGOutput->resource->setData(this);
if (!PMONITOR)
return;
const auto XDGVER = pXDGOutput->resource->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) {
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
if (!pOutput->resource->good())
if (!pOutput->resource->good() || !pOutput->monitor)
return;
const auto POS = pOutput->isXWayland ? pOutput->monitor->vecXWaylandPosition : pOutput->monitor->vecPosition;
@@ -133,6 +131,10 @@ void CXDGOutputProtocol::updateOutputDetails(SXDGOutput* pOutput) {
void CXDGOutputProtocol::updateAllOutputs() {
for (auto& o : m_vXDGOutputs) {
if (!o->monitor)
continue;
updateOutputDetails(o.get());
wlr_output_schedule_done(o->monitor->output);

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