Compare commits

...

133 Commits

Author SHA1 Message Date
Vaxry
0bd541f2fd version: bump to 0.46.2 2024-12-19 19:26:47 +00:00
Aqa-Ib
23d00cdd0d layout: apply group rules after window creation (#8779)
* apply group rules after window creation

* clang-format
2024-12-19 19:26:40 +00:00
Vaxry
061241d3a2 core: fix possible crash on null active workspace
fixes #7822
2024-12-19 19:26:40 +00:00
Aaron Blasko
b9df70be22 hyprpm: fix hyrpm sometimes returning 0 despite errors occuring (#8761)
* hyprpm: fix hyrpm sometimes returning 0 despite errors occuring

* there u go
2024-12-19 19:26:40 +00:00
Jan Beich
9583429eae core: Unbreak build on FreeBSD (#8762)
* CrashReporter: restore explicit environ(7) after 8bbeee1173

BSD systems don't declare environ(7) in any header like POSIX suggests.

src/signal-safe.cpp:12:23: error: use of undeclared identifier 'environ'
   12 |     for (char** var = environ; *var != nullptr; var++) {
      |                       ^

* fix

---------

Co-authored-by: Vaxry <vaxry@vaxry.net>
2024-12-19 19:26:40 +00:00
Vaxry
747c38112b xwayland: fix compile with no xwayland 2024-12-19 19:26:40 +00:00
Vaxry
508e82341f xwm: fixup targets in selection requests
fixes #8719
2024-12-19 19:26:40 +00:00
Vaxry
ec0a38303b xwayland: fix dnd including xwayland
ref #8759
2024-12-19 19:26:40 +00:00
Vaxry
d0bffc4fa9 core: avoid activating toplevel-less surfaces
ref #8609
2024-12-19 19:26:40 +00:00
Khalid
07a19e2c95 hyprctl: Fix hyprctl batch JSON command (#8749) 2024-12-19 19:26:40 +00:00
Vaxry
46d5b363fa windowrules: fixup duplicate rule enum tags
fixes #8746
2024-12-19 19:26:40 +00:00
Vaxry
788ae58897 version: bump to 0.46.0 2024-12-16 23:38:56 +00:00
Vaxry
bba2d9a197 versionkeeper: init version to 0.0.0 if no file is present 2024-12-16 23:37:13 +00:00
Austin Horstman
e340e9f431 nix/meson: add re2 dependency (#8738)
* nix/default: add re2 dependency

* meson: add re2
2024-12-16 20:22:36 +01:00
Vaxry
c2d14a2013 opengl: fixup missed /4 in oklab parsing 2024-12-16 18:53:21 +00:00
Vaxry
95cdedee04 windowrules: fix prop rules with boolean values 2024-12-16 18:44:19 +00:00
Vaxry
0706c1a1f7 layerrules: fix ignorezero not working
fixes #8737
2024-12-16 18:37:34 +00:00
Vaxry
aecf1abddd opengl: fixup invalid ogl uniform reads 2024-12-16 18:34:19 +00:00
Vaxry
b9f82e9968 animationmgr: fixup stack-use-after-return 2024-12-16 18:31:07 +00:00
Vaxry
e06b520427 core: Move regex from stdlib to re2 (#8736)
Moves the regex handling from stdlib to re2
2024-12-16 19:21:44 +01:00
Vaxry
dab50b3ef3 core: Optimize window/layer rule application and scanning (#8735)
Optimizes window and layer rule parsing and later usage.
2024-12-16 19:05:24 +01:00
Mihai Fufezan
eaac5c7cbd flake.lock: update 2024-12-16 18:06:00 +02:00
Vaxry
a5234f26e4 core: drop using deques in favor of vectors
No point in most of these.
2024-12-16 15:58:19 +00:00
Vaxry
de3ad245dc input: add warp_back_after_non_mouse_input
adds cursor:warp_back_after_non_mouse_input

fixes #8675
2024-12-15 23:54:14 +00:00
Vaxry
db24964877 xwayland: Support cross DnD from Wayland (#8708)
Adds support for drag-and-drop from Wayland clients to XWayland ones
2024-12-15 00:37:17 +01:00
Vaxry
9f7a96b997 core/data: Use pointer focus for DnD operations (#8707)
fixes #7737
2024-12-14 16:19:56 +01:00
Vaxry
3cba4ba44e hyprctl: avoid crash on null pwuid
fixes #8693
2024-12-13 22:36:42 +00:00
Vaxry
8237627f3a compositor: fix monitor arrangement with mixed auto directions
fixes #8518
2024-12-13 22:31:30 +00:00
Vaxry
35e134e570 hyprctl: add an inhibitingIdle field to windows
fixes #4322
2024-12-13 21:30:24 +00:00
normaltaro
452a7e6905 dispatchers: Add an option to prioritize focus change within groups with movefocus (#8601)
* modified movefocus dispatcher to prioritize focus change within groups

* pass clang-format check

* `movefocus` cycling groups set optional to config bool `movefocus_cycles_groupfirst`

* Update ConfigDescriptions.hpp
2024-12-13 21:28:57 +01:00
Mike Will
61a51bb4ef snap: bias reserved area when its size is greater than zero (#8694) 2024-12-13 17:34:04 +01:00
Vaxry
aefaeedf5e data-device: fixup wrong box expansion
oopsie 7c03e9d376 was wrong
2024-12-12 12:16:59 +00:00
Vaxry
cef5e6dd7c layersurface: use lastMonitor and not monitor from cursor for new ls
fixes #8622
2024-12-11 22:31:38 +00:00
Vaxry
7c03e9d376 core/data-device: expand damage region to fix minor px errors
fixes #7656
2024-12-11 22:30:17 +00:00
Mike Will
df956a0f6f windowrules: add rules for mouse and touchpad scroll factors (#8655) 2024-12-11 17:27:49 +00:00
rooot
33f271c29a hyprpm: target installed instead of running version (#8634)
---------

Signed-off-by: rooot <hey@rooot.gay>
2024-12-11 17:49:09 +01:00
Vaxry
e892310953 workspace: update hasFullscreenWindow in updateWindows 2024-12-11 16:03:04 +00:00
Pavel Belyavsky
4d05677e8d config: add 'force' option for 'cursor:warp_on_change_workspace' (#8681)
* config: add 'force' option for 'cursor:warp_on_change_workspace'

* manager: throw the expression into the function arguments

* config: fix description of `cursor:warp_on_change_workspace`
2024-12-10 21:55:05 +01:00
Alexander Iliev
c16044a5c8 core: Fix workspace selector parsing (#8687)
Search for the closing bracket when parsing a workspace selector.
This is needed when the `m[desc:<monitor description>]` selector
is used, as the monitor description always contains spaces.
2024-12-10 21:54:51 +01:00
littleblack111
d94d8b4ab2 windows: allow replacing existing fullscreen (#8566)
* feat: `binds:allow_replace_fullscreen`

this allows replacement of fullscreen window(i.e. fullscreening another
window when one is already fullscreened on the workspace)

this is used when a floating window that is spawned on top of a
fullscreen wanted to be fullscreened

* clang-format

* remove: config for `allow_replace_fullscreen`
2024-12-10 21:09:47 +01:00
Vaxry
bb5c3f2702 core/output: don't send enter too aggresively
sometimes this might be like 1px and send enter to the wrong output

fixes #8654
2024-12-10 01:40:35 +00:00
Vaxry
0a27af8cd1 crashreporter: avoid clang warning 2024-12-08 18:52:39 +00:00
Mihai Fufezan
c106f454c1 CI/Nix: temporarily disable cross build 2024-12-07 22:01:32 +02:00
Vaxry
875b598a33 github: mention PR guidelines in the template 2024-12-07 18:01:19 +00:00
Vaxry
8bbeee1173 core: Add clang-tidy (#8664)
This adds a .clang-tidy file for us.

It's not a strict requirement to be compliant, but I tuned it to be alright.
2024-12-07 18:51:18 +01:00
Vaxry
b1e5cc66bd core: Add support for hyprqtutils' update screen (#8651)
* Nix: add hyprland-qtutils to PATH

* flake.lock: update

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-12-06 15:45:02 +01:00
Mike Will
5ff02902ee snap: use the bit mask to check if snapping occurred (#8659) 2024-12-06 15:25:14 +01:00
Vaxry
cccca7c02e renderer: drop requesting OUT_FENCE_PTR 2024-12-06 14:15:46 +00:00
Mihai Fufezan
10a4365f7d Nix: create TAG info from version 2024-12-06 10:16:18 +02:00
Vaxry
a7a6eedc21 core: move version include to hyprctl 2024-12-05 19:35:50 +00:00
Vaxry
888bdf4e23 hyprctl: add directScanout to hyprctl monitors 2024-12-05 19:33:54 +00:00
Vaxry
ceef4fb3a5 core: feeling a bit quirky today. 2024-12-05 03:36:50 +00:00
Vaxry
22f7d6f142 core: add a few festive splashes
adds two new 'special' splash types for xmas and new years. Activated based on local time.
2024-12-05 01:59:36 +00:00
Mike Will
f9e4998a6d snap: check which corner is being grabbed for monitor snapping (#8637) 2024-12-04 19:12:04 +01:00
Vaxry
3c617ce33c internal: fixup some missed updateColorsOk() calls 2024-12-03 22:58:30 +00:00
vaxerski
f6ac755cf7 cleanup: Revert use doLater instead of adding idle event handlers (#8624)
This reverts commit 6d7544458d.
2024-12-03 21:15:25 +00:00
Vaxry
320144ae72 core: move colorspace handling to oklab (#8635)
* Meson: add hyprgraphics

* Nix: add hyprgraphics

* CI/setup_base: get hyprgraphics-git

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-12-03 18:58:24 +00:00
Vaxry
92186898c0 version: add link versions for other utils (#8619)
---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-12-02 16:31:22 +00:00
UjinT34
10a9fec7fc master: make center ignore reserved areas (#8625) 2024-12-02 15:32:32 +00:00
Ikalco
6d7544458d cleanup: use doLater instead of adding idle event handlers (#8624) 2024-12-01 17:14:35 +00:00
Vaxry
d26439a0fe nix: update flake 2024-11-30 17:42:40 +00:00
littleblack111
ef6b0c81c9 cleanup: remove leftover var in ThreadManager.cpp (#8611) 2024-11-30 16:40:23 +00:00
Vaxry
8f83d29f00 renderer: restore discard mode after IME render pass
ref #8555
2024-11-28 23:51:59 +00:00
Daringcuteseal
22bf2853e6 hyprpm: fix incomplete unmet dependencies message 2024-11-28 17:48:46 +02:00
nyx
5963970be5 descriptions: change allow_pin_fullscreen value to false (#8592) 2024-11-28 15:25:24 +00:00
Vaxry
8b51eeb7ae core: fix compilation outside stdlibc++
fixes #8603
2024-11-28 14:31:43 +00:00
Andre Toerien
5329298b52 sessionLock: don't send motion events on every surface commit (#8584) 2024-11-27 19:59:00 +00:00
Agent00Ming
e9a7fb8f91 renderer: fix incorrect early return (#8590)
Co-authored-by: Agent_00Ming <agent00ming9366@gmail.com>
2024-11-27 14:17:45 +00:00
Ikalco
1fb720b62a seat: fix double scrolling in some applications (#8583) 2024-11-26 13:52:43 +00:00
Vaxry
2687788236 hyprctl: verify runtime dir exists in instances()
ref #8579
2024-11-25 14:42:11 +00:00
Vladimir-csp
0ddb952d7a hyprland-uwsm.desktop: Just reference plain entry (#8553) 2024-11-25 16:18:50 +02:00
Nabil Otsmane
1930a95000 shm: fix shm fd size check before creating or resizing shm_pool (#8572)
* protocols: fix shm fd size check before creating or resizing shm_pool

* added static to function
2024-11-25 00:50:35 +00:00
Vaxry
cc38e7e18f config: don't overwrite errors in gradients 2024-11-24 14:53:36 +00:00
Vaxry
55ec8bd512 config: throw an error explicitly when parsing colors in gradients
ref #8552
2024-11-24 02:46:28 +00:00
Mike Will
54f57797e9 snap: account for position of multiple monitors (#8543) 2024-11-23 14:36:28 +00:00
littleblack111
65f66dcf0d binds: add option to allow fullscreening a pinned window (#8526) 2024-11-23 14:32:13 +00:00
Ryan
451d7a41fc renderer: add option to blur IME popups (#8521) 2024-11-23 14:29:29 +00:00
Vaxry
00d6261cc0 hyprpm: move temp files to XDG_RUNTIME_DIR
avoid /tmp, it's cringe
2024-11-23 14:18:13 +00:00
Vaxry
745a82ce8a core: workspace-related function cleanup / refactor
CCompositor is massive, and has a lot of functions that could be better optimized if in CWorkspace
2024-11-22 16:01:02 +00:00
Vaxry
a847bc67b1 monitor: fix default focus when switching to a fs workspace 2024-11-22 15:22:35 +00:00
may
b100344595 keybinds: actually suppress internal keybinds instead of passing them along (#8538) 2024-11-22 02:31:42 +00:00
Tom Englund
943b3d467b bezier: optimize setup of bezier curves (#8528)
avoid reallocations by resizing and copy the pVec into the resized
m_dPoints, reduce the amount of calculations in baking to only do it
once per iteration instead of twice. precompute in getYforT and getXforT
return early in getYForPoint if x is equal or below 0. and use const
references where we can.

these changes we are now down to an average of "time to bake: 2.50µs."
on my machine compared to before average of "time to bake: 11.15µs"
2024-11-22 01:47:51 +00:00
vaxerski
940f7aa990 renderer: fixup blur optimization considitons
fixes #8531
2024-11-20 11:02:21 +00:00
Vaxry
e5fa017172 internal: fix some misused configStringToInt conversions
fixes #8523
2024-11-20 10:32:50 +00:00
Vaxry
c4eda46d0e xdg-shell: even more robust layout min/max size
although I don't think any apps use this, but better safe than sorry
2024-11-19 22:07:25 +00:00
Vaxry
aa067a4cf1 xdg-shell: don't report invalid min/max sizes on unset
fixes #8522
2024-11-19 21:40:16 +00:00
Vaxry
67cee43006 internal: minor cleanups for color results 2024-11-19 01:16:11 +00:00
Vaxry
47a1650c48 miscfunctions: move configStringToInt to std::expected 2024-11-18 23:53:38 +00:00
Vaxry
936dfedbad keybinds: move to managed pointers 2024-11-18 19:56:26 +00:00
MightyPlaza
6113f4da7f keybinds: allow repeating multiple binds (#8290) 2024-11-18 19:48:13 +00:00
Maximilian Seidler
cc923ad031 config: update the configStringToInt implementation (#8476)
Copied from hyprlang and removed std::expected.
2024-11-18 19:45:22 +00:00
🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко)
df9ff44899 Fix example config name in auto-generated cfg header (#8509)
Previously, it was suggesting to find `hypr.conf` in the `examples/` folder which doesn't exist. This patch fixed that to point to the existing file.

Additionally, the change updates `HYPR` to `HYPRLAND` in the same header.
2024-11-18 17:54:18 +02:00
Aqa-Ib
97493511f9 internal: fix changeWindowZOrder reordering incorrectly (#8494) 2024-11-18 14:44:15 +00:00
Vaxry
505c1f8f4a miscfunctions: fix cross build 2024-11-18 14:35:09 +00:00
johannes hanika
6744bb57c6 constraints: don't warp pointer position on release (#8491)
this was annoying for nuklear properties/ui slider elements that grab
the pointer via GLFW_CURSOR_DISABLE to allow more range and finer control.
upon mouse release, the pointer is reset to the middle of the window
without this patch, making long mouse movements necessary to go back
to the original position for readjustments. fwiw the new behaviour
is consistent with x11 and weston.
2024-11-18 14:02:34 +00:00
Vaxry
2259a88551 miscfunctions: add missing include 2024-11-18 13:59:57 +00:00
Vaxry
1ba050d603 shell: propagate new machanism from hyprctl to miscfunctions 2024-11-17 21:58:00 +00:00
Vaxry
e8717a4fce shell: don't use fgrep, prefer grep -F 2024-11-17 21:57:04 +00:00
Alessio Molinari
9b03307653 hooks: add pre connected/disconnected monitor events (#8503) 2024-11-17 19:34:03 +00:00
Vaxry
b735295d2b windows/xdg: minor cleanup of min/max size calculations
fixes #8495
2024-11-17 19:31:54 +00:00
Vaxry
8d5cdedbd3 hyprpm: fix format crash
ref #8487
2024-11-17 16:46:49 +00:00
Vaxry
4f591e807a renderer: simplify blur enabling logic 2024-11-17 16:42:30 +00:00
Vaxry
fb91c2550f renderer: don't render unmapped popups
fixes #8485
2024-11-17 16:16:54 +00:00
Alexandre Acebedo
0ddbd1c3a4 renderer: add lockdead_screen_delay (#8467) 2024-11-17 15:58:18 +00:00
Ruslan
af83c82513 hyprctl: add json output on hyprctl -j plugins list (#8480)
---------

Co-authored-by: Руслан Новокшонов <r.novokshonov@vk.team>
2024-11-16 23:18:30 +00:00
staz
9d37b1b073 workspacerules: Do not check 'on-created-empty' if using a workspace windowrule (#8486) 2024-11-16 23:07:33 +00:00
vaxerski
cf18eca86d [gha] Nix: update inputs 2024-11-16 23:06:35 +00:00
Vaxry
ec1e6be003 core: guard pmonitor in focuswindow
may be null

fixes #8483
2024-11-16 23:05:02 +00:00
sslater11
83be2480c4 workspace: fix missing name via focusworkspaceoncurrentmonitor (#8484) 2024-11-16 16:39:58 +00:00
littleblack111
7affc34ab4 bind: new long press option (#8302)
---------

Co-authored-by: Vaxry <vaxry@vaxry.net>
2024-11-15 23:21:59 +00:00
Vaxry
098e491a43 protocols: mark primarySelection as not privileged
fixes #8479
2024-11-15 00:47:34 +00:00
UjinT34
967fe76a60 drm: enable explit out fence in AQ (#8431) 2024-11-15 00:45:13 +00:00
Tom Englund
940ed3d525 xcursors: store themes in a std:set to order it (#8474)
using a unordered_set means its store based on a hash_value meaning
currently it can end up loading inherited themes before the actual theme
itself depending on the hash of the theme name used, reason for using
set at all over vector is to keep unique members and not foreverever
looping broken inherit themeing.
2024-11-14 20:38:16 +00:00
Vaxry
6f7280a690 descriptions: add use_cpu_buffer 2024-11-14 20:20:51 +00:00
Vaxry
20031cea92 pointer: add drm dumb buffers for cursors (#8399)
---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-11-14 20:15:51 +00:00
Mihai Fufezan
3fb47372b7 flake.lock: update 2024-11-13 21:34:52 +02:00
Vaxry
bb160cfe37 makefile: add stub to discourage direct make 2024-11-12 15:26:25 +00:00
SoSeDiK
a29cfa7843 logging: Add some context to config error logs (#8326) 2024-11-12 00:53:55 +00:00
nnra
f5fa84554f config: Changed the default value of decoration:blur:ignore_opacity to true (#8418)
This change is made in order to deliver the blur look majority of people
expect by default.
2024-11-11 15:49:35 +00:00
Mihai Fufezan
b88e4a1a9a Nix: disable uwsm desktop file installation
Will be enabled in the NixOS module.
2024-11-11 16:52:42 +02:00
Mihai Fufezan
ff411658e8 Lock uwsm desktop file behind feature flag
The file in the repo cannot be used in NixOS due to missing full paths,
and the fact that `uwsm` does not have access to `PATH` to find the
listed binaries. Might be useful in other situations as well.
2024-11-11 16:52:42 +02:00
Mihai Fufezan
943c7d18cc meson: autodetect systemd 2024-11-11 16:52:42 +02:00
Izmyname
ccfae82ad1 rename hyprland-systemd.desktop and remove hyprland-session.service 2024-11-11 16:52:42 +02:00
izmyname
430b5c302a systemd: hyprland-systemd.desktop -> hyprland-uwsm.desktop
Remove hyprland-session.service.
2024-11-11 16:52:42 +02:00
Vaxry
8fa4cfb7df keybinds: don't animate fullscreen size/pos changes coming in
when fullscreen, don't animate the pos/size when switching to another fullscreen window, as they can look weird and distracting.

Ideally we would do it differently but it's not really possible to do well without reading minds
2024-11-11 13:55:37 +00:00
dawsers
a551f85b91 renderer: scaled surfaces could have zero area (#8423) 2024-11-11 13:48:50 +00:00
JManch
07052a515b pointer: map devices across all outputs by default (#8352) 2024-11-11 13:45:33 +00:00
WavyEbuilder
1fa0cd7a75 debug: clean up fetching of the contents of /proc/device-tree (#8413) 2024-11-11 13:44:41 +00:00
Vaxry
c10739e6e3 core: fixup execAndGet
fixes #8410
2024-11-10 22:53:11 +00:00
WavyEbuilder
9e628067fc debug: clean up opening of files in HyprCtl (#8401)
`std::ifstream` is more suited than `execAndGet` here.
2024-11-10 15:54:15 +00:00
Vaxry
99b01c5d12 hyprpm: fix format 2024-11-10 15:54:00 +00:00
Vaxry
a8ff3a452c core: move to os/Process from hyprutils
nix bump too
2024-11-09 17:14:25 +00:00
Vaxry
dca75db127 defaultConfig: fixup smart gaps rules 2024-11-09 16:56:43 +00:00
197 changed files with 4949 additions and 2782 deletions

101
.clang-tidy Normal file
View File

@@ -0,0 +1,101 @@
WarningsAsErrors: '*'
HeaderFilterRegex: '.*\.hpp'
FormatStyle: file
Checks: >
-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
-bugprone-forward-declararion-namespace,
-bugprone-forward-declararion-namespace,
-bugprone-macro-parentheses,
-bugprone-narrowing-conversions,
-bugprone-branch-clone,
-bugprone-assignment-in-if-condition,
concurrency-*,
-concurrency-mt-unsafe,
cppcoreguidelines-*,
-cppcoreguidelines-owning-memory,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-avoid-const-or-ref-data-members,
-cppcoreguidelines-non-private-member-variables-in-classes,
-cppcoreguidelines-avoid-goto,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-special-member-functions,
-cppcoreguidelines-explicit-virtual-functions,
-cppcoreguidelines-avoid-c-arrays,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-narrowing-conversions,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-member-init,
-cppcoreguidelines-macro-usage,
-cppcoreguidelines-macro-to-enum,
-cppcoreguidelines-init-variables,
-cppcoreguidelines-pro-type-cstyle-cast,
-cppcoreguidelines-pro-type-vararg,
-cppcoreguidelines-pro-type-reinterpret-cast,
google-global-names-in-headers,
-google-readability-casting,
google-runtime-operator,
misc-*,
-misc-unused-parameters,
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
-misc-include-cleaner,
-misc-use-anonymous-namespace,
-misc-const-correctness,
modernize-*,
-modernize-return-braced-init-list,
-modernize-use-trailing-return-type,
-modernize-use-using,
-modernize-use-override,
-modernize-avoid-c-arrays,
-modernize-macro-to-enum,
-modernize-loop-convert,
-modernize-use-nodiscard,
-modernize-pass-by-value,
-modernize-use-auto,
performance-*,
-performance-avoid-endl,
-performance-unnecessary-value-param,
portability-std-allocator-const,
readability-*,
-readability-function-cognitive-complexity,
-readability-function-size,
-readability-identifier-length,
-readability-magic-numbers,
-readability-uppercase-literal-suffix,
-readability-braces-around-statements,
-readability-redundant-access-specifiers,
-readability-else-after-return,
-readability-container-data-pointer,
-readability-implicit-bool-conversion,
-readability-avoid-nested-conditional-operator,
-readability-redundant-member-init,
-readability-redundant-string-init,
-readability-avoid-const-params-in-decls,
-readability-named-parameter,
-readability-convert-member-functions-to-static,
-readability-qualified-auto,
-readability-make-member-function-const,
-readability-isolate-declaration,
-readability-inconsistent-declaration-parameter-name,
-clang-diagnostic-error,
CheckOptions:
performance-for-range-copy.WarnOnAllAutoCopies: true
performance-inefficient-string-concatenation.StrictMode: true
readability-braces-around-statements.ShortStatementLines: 0
readability-identifier-naming.ClassCase: CamelCase
readability-identifier-naming.ClassIgnoredRegexp: I.*
readability-identifier-naming.ClassPrefix: C # We can't use regex here?!?!?!?
readability-identifier-naming.EnumCase: CamelCase
readability-identifier-naming.EnumPrefix: e
readability-identifier-naming.EnumConstantCase: UPPER_CASE
readability-identifier-naming.FunctionCase: camelBack
readability-identifier-naming.NamespaceCase: CamelCase
readability-identifier-naming.NamespacePrefix: N
readability-identifier-naming.StructPrefix: S
readability-identifier-naming.StructCase: CamelCase

View File

@@ -33,7 +33,9 @@ runs:
libfontenc \
libglvnd \
libinput \
libjxl \
libliftoff \
libwebp \
libxcursor \
libxcvt \
libxfont2 \
@@ -58,7 +60,8 @@ runs:
xcb-util \
xcb-util-image \
libzip \
librsvg
librsvg \
re2
- name: Get hyprwayland-scanner-git
shell: bash
@@ -69,6 +72,11 @@ runs:
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
cmake --install build
- name: Get hyprgraphics-git
shell: bash
run: |
git clone https://github.com/hyprwm/hyprgraphics && cd hyprgraphics && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprgraphics && cmake --install build
- name: Get hyprutils-git
shell: bash
run: |

View File

@@ -1,3 +1,9 @@
<!--
BEFORE you submit your PR, please check out the PR guidelines
on our wiki: https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/
-->
#### Describe your PR, what does it fix/add?

View File

@@ -12,7 +12,8 @@ jobs:
matrix:
package:
- hyprland
- hyprland-cross
# - hyprland-cross # cross compiling fails due to qt
# failure chain: hyprland-qtutils -> qt6.qtsvg -> qt6.qtbase -> psqlodbc & qt6.qttranslations
- xdg-desktop-portal-hyprland
runs-on: ubuntu-latest

View File

@@ -101,11 +101,17 @@ else()
endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1)
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.2)
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5)
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2)
pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7)
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.2.3)
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}")
add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}")
add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}")
add_compile_definitions(HYPRGRAPHICS_VERSION="${hyprgraphics_dep_VERSION}")
pkg_check_modules(
deps
@@ -124,9 +130,7 @@ pkg_check_modules(
libinput
gbm
gio-2.0
hyprlang>=0.3.2
hyprcursor>=0.1.7
hyprutils>=0.2.3)
re2)
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -222,16 +226,15 @@ if(NO_SYSTEMD)
else()
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
add_compile_definitions(USES_SYSTEMD)
configure_file(systemd/hyprland-session.service.in
systemd/hyprland-session.service @ONLY)
# session file -systemd
install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-systemd.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
# install systemd service
install(FILES ${CMAKE_BINARY_DIR}/systemd/hyprland-session.service
DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/user)
# session file -uwsm
if(NO_UWSM)
message(STATUS "UWSM support is disabled...")
else()
message(STATUS "UWSM support is enabled (NO_UWSM not defined)...")
install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
endif()
endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
@@ -245,7 +248,7 @@ target_precompile_headers(Hyprland PRIVATE
message(STATUS "Setting link libraries")
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps)
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::hyprgraphics_dep PkgConfig::deps)
if(udis_dep_FOUND)
target_link_libraries(Hyprland PkgConfig::udis_dep)
else()

View File

@@ -1,5 +1,8 @@
PREFIX = /usr/local
stub:
@echo "Do not run $(MAKE) directly without any arguments. Please refer to the wiki on how to compile Hyprland."
legacyrenderer:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`

View File

@@ -1 +1 @@
0.45.0
0.46.2

View File

@@ -136,13 +136,10 @@ animations {
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[t1], gapsout:0, gapsin:0
# workspace = w[tg1], gapsout:0, gapsin:0
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[t1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[t1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tg1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tg1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]

96
flake.lock generated
View File

@@ -16,11 +16,11 @@
]
},
"locked": {
"lastModified": 1730968822,
"narHash": "sha256-NocDjINsh6ismkhb0Xr6xPRksmhuB2WGf8ZmXMhxu7Y=",
"lastModified": 1734364797,
"narHash": "sha256-2h1c+P0v3l0Z/ypUSsAPhU/yiSRgFwjVFODWp0S3d/w=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "a49bc3583ff223f426cb3526fdaa4bcaa247ec14",
"rev": "8e77618b403a82fde2105a8e3cd7cabe7ef00952",
"type": "github"
},
"original": {
@@ -79,11 +79,11 @@
]
},
"locked": {
"lastModified": 1728669738,
"narHash": "sha256-EDNAU9AYcx8OupUzbTbWE1d3HYdeG0wO6Msg3iL1muk=",
"lastModified": 1734364709,
"narHash": "sha256-+2bZJL2u5hva7rSp65OfKJBK+k03T6GB/NCvpoS1OOo=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "0264e698149fcb857a66a53018157b41f8d97bb0",
"rev": "f388aacd22be4a6e4d634fbaf6f75eb0713d239a",
"type": "github"
},
"original": {
@@ -92,6 +92,32 @@
"type": "github"
}
},
"hyprgraphics": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1733684019,
"narHash": "sha256-2kYREgmSmbLsmDpLEq96hxVAU3qz8aCvVhF65yCFZHY=",
"owner": "hyprwm",
"repo": "hyprgraphics",
"rev": "fb2c0268645a77403af3b8a4ce8fa7ba5917f15d",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprgraphics",
"type": "github"
}
},
"hyprland-protocols": {
"inputs": {
"nixpkgs": [
@@ -115,6 +141,32 @@
"type": "github"
}
},
"hyprland-qtutils": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1733940128,
"narHash": "sha256-hmfXWj2GA9cj1QUkPFYtAAeohhs615zL4E3APy3FnvQ=",
"owner": "hyprwm",
"repo": "hyprland-qtutils",
"rev": "3833097e50473a152dd614d4b468886840b4ea78",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-qtutils",
"type": "github"
}
},
"hyprlang": {
"inputs": {
"hyprutils": [
@@ -128,11 +180,11 @@
]
},
"locked": {
"lastModified": 1728168612,
"narHash": "sha256-AnB1KfiXINmuiW7BALYrKqcjCnsLZPifhb/7BsfPbns=",
"lastModified": 1734364628,
"narHash": "sha256-ii8fzJfI953n/EmIxVvq64ZAwhvwuuPHWfGd61/mJG8=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "f054f2e44d6a0b74607a6bc0f52dba337a3db38e",
"rev": "16e59c1eb13d9fb6de066f54e7555eb5e8a4aba5",
"type": "github"
},
"original": {
@@ -151,11 +203,11 @@
]
},
"locked": {
"lastModified": 1730968903,
"narHash": "sha256-zFvzLXcSm0Ia4XI1SE4FQ9KE63hlGrRWhLtwMolWuR8=",
"lastModified": 1733502241,
"narHash": "sha256-KAUNC4Dgq8WQjYov5auBw/usaHixhacvb7cRDd0AG/k=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "3ce0cde8709cdacbfba471f8e828433b58a561e9",
"rev": "104117aed6dd68561be38b50f218190aa47f2cd8",
"type": "github"
},
"original": {
@@ -189,11 +241,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1730785428,
"narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=",
"lastModified": 1734119587,
"narHash": "sha256-AKU6qqskl0yf2+JdRdD0cfxX4b9x3KKV5RqA6wijmPM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7",
"rev": "3566ab7246670a43abd2ffa913cc62dad9cdf7d5",
"type": "github"
},
"original": {
@@ -229,11 +281,11 @@
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1730814269,
"narHash": "sha256-fWPHyhYE6xvMI1eGY3pwBTq85wcy1YXqdzTZF+06nOg=",
"lastModified": 1734279981,
"narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "d70155fdc00df4628446352fc58adc640cd705c2",
"rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785",
"type": "github"
},
"original": {
@@ -246,7 +298,9 @@
"inputs": {
"aquamarine": "aquamarine",
"hyprcursor": "hyprcursor",
"hyprgraphics": "hyprgraphics",
"hyprland-protocols": "hyprland-protocols",
"hyprland-qtutils": "hyprland-qtutils",
"hyprlang": "hyprlang",
"hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner",
@@ -293,11 +347,11 @@
]
},
"locked": {
"lastModified": 1730743262,
"narHash": "sha256-iTLqj3lU8kFehPm5tXpctzkD274t/k1nwSSq3qCWXeg=",
"lastModified": 1734124279,
"narHash": "sha256-YNpFfiQjYt2o6LGcMN9NkjVvprC8ELrIpLHlbZbclRM=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "09b23cef06fe248e61cec8862c04b9bcb62f4b6d",
"rev": "0c6861f819f6d31f6195c9864709b2556f00b5cf",
"type": "github"
},
"original": {

View File

@@ -22,12 +22,26 @@
inputs.hyprlang.follows = "hyprlang";
};
hyprgraphics = {
url = "github:hyprwm/hyprgraphics";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
};
hyprland-protocols = {
url = "github:hyprwm/hyprland-protocols";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
hyprland-qtutils = {
url = "github:hyprwm/hyprland-qtutils";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
};
hyprlang = {
url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs";
@@ -116,13 +130,11 @@
inherit
(pkgsFor.${system})
# hyprland-packages
hyprland
hyprland-debug
hyprland-legacy-renderer
hyprland-unwrapped
# hyprland-extras
xdg-desktop-portal-hyprland
;
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;

View File

@@ -5,7 +5,7 @@ project(
DESCRIPTION "Control utility for Hyprland"
)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1)
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.4 re2)
add_executable(hyprctl "main.cpp")

View File

@@ -1,3 +1,5 @@
#include <re2/re2.h>
#include <cctype>
#include <netdb.h>
#include <netinet/in.h>
@@ -21,10 +23,8 @@
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <filesystem>
#include <cstdarg>
#include <regex>
#include <sys/socket.h>
#include <hyprutils/string/String.hpp>
#include <cstring>
@@ -52,11 +52,17 @@ void log(const std::string& str) {
std::println("{}", str);
}
static int getUID() {
const auto UID = getuid();
const auto PWUID = getpwuid(UID);
return PWUID ? PWUID->pw_uid : UID;
}
std::string getRuntimeDir() {
const auto XDG = getenv("XDG_RUNTIME_DIR");
if (!XDG) {
const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
const std::string USERID = std::to_string(getUID());
return "/run/user/" + USERID + "/hypr";
}
@@ -66,6 +72,11 @@ std::string getRuntimeDir() {
std::vector<SInstanceData> instances() {
std::vector<SInstanceData> result;
try {
if (!std::filesystem::exists(getRuntimeDir()))
return {};
} catch (std::exception& e) { return {}; }
for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) {
if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock"))
continue;
@@ -163,7 +174,7 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) {
return 2;
}
const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
const std::string USERID = std::to_string(getUID());
sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX;
@@ -233,7 +244,7 @@ int requestHyprpaper(std::string arg) {
sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX;
const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
const std::string USERID = std::to_string(getUID());
std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock";
@@ -271,10 +282,11 @@ int requestHyprpaper(std::string arg) {
}
void batchRequest(std::string arg, bool json) {
std::string commands = arg.substr(arg.find_first_of(" ") + 1);
std::string commands = arg.substr(arg.find_first_of(' ') + 1);
if (json) {
commands = "j/" + std::regex_replace(commands, std::regex(";\\s*"), ";j/");
RE2::GlobalReplace(&commands, ";\\s*", ";j/");
commands.insert(0, "j/");
}
std::string rq = "[[BATCH]]" + commands;
@@ -311,11 +323,11 @@ void instancesRequest(bool json) {
log(result + "\n");
}
std::deque<std::string> splitArgs(int argc, char** argv) {
std::deque<std::string> result;
std::vector<std::string> splitArgs(int argc, char** argv) {
std::vector<std::string> result;
for (auto i = 1 /* skip the executable */; i < argc; ++i)
result.push_back(std::string(argv[i]));
result.emplace_back(argv[i]);
return result;
}

View File

@@ -3,6 +3,7 @@ executable(
'main.cpp',
dependencies: [
dependency('hyprutils', version: '>= 0.1.1'),
dependency('re2', required: true)
],
install: true,
)

View File

@@ -9,11 +9,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
set(CMAKE_CXX_STANDARD 23)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1)
pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4)
add_executable(hyprpm ${SRCFILES})
target_link_libraries(hyprpm PUBLIC PkgConfig::deps)
target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps)
# binary
install(TARGETS hyprpm)

View File

@@ -23,35 +23,53 @@
#include <toml++/toml.hpp>
#include <hyprutils/string/String.hpp>
#include <hyprutils/os/Process.hpp>
using namespace Hyprutils::String;
using namespace Hyprutils::OS;
static std::string execAndGet(std::string cmd) {
cmd += " 2>&1";
std::array<char, 128> buffer;
std::string result;
using PcloseType = int (*)(FILE*);
const std::unique_ptr<FILE, PcloseType> pipe(popen(cmd.c_str(), "r"), static_cast<PcloseType>(pclose));
if (!pipe)
return "";
result.reserve(buffer.size());
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
CProcess proc("/bin/sh", {"-c", cmd});
if (!proc.runSync())
return "error";
return proc.stdOut();
}
SHyprlandVersion CPluginManager::getHyprlandVersion() {
static SHyprlandVersion ver;
static bool once = false;
static std::string getTempRoot() {
static auto ENV = getenv("XDG_RUNTIME_DIR");
if (!ENV) {
std::cerr << "\nERROR: XDG_RUNTIME_DIR not set!\n";
exit(1);
}
if (once)
return ver;
const auto STR = ENV + std::string{"/hyprpm/"};
once = true;
const auto HLVERCALL = execAndGet("hyprctl version");
return STR;
}
SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
static bool onceRunning = false;
static bool onceInstalled = false;
static SHyprlandVersion verRunning;
static SHyprlandVersion verInstalled;
if (onceRunning && running)
return verRunning;
if (onceInstalled && !running)
return verInstalled;
if (running)
onceRunning = true;
else
onceInstalled = true;
const auto HLVERCALL = running ? execAndGet("hyprctl version") : execAndGet("Hyprland --version");
if (m_bVerbose)
std::println("{}", verboseString("version returned: {}", HLVERCALL));
std::println("{}", verboseString("{} version returned: {}", running ? "running" : "installed", HLVERCALL));
if (!HLVERCALL.contains("Tag:")) {
std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland."));
@@ -82,12 +100,18 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
if (m_bVerbose)
std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits));
ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
auto ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
if (running)
verRunning = ver;
else
verInstalled = ver;
return ver;
}
bool CPluginManager::createSafeDirectory(const std::string& path) {
if (path.empty() || !path.starts_with("/tmp"))
if (path.empty() || !path.starts_with(getTempRoot()))
return false;
if (std::filesystem::exists(path))
@@ -106,7 +130,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HLVER = getHyprlandVersion();
if (!hasDeps()) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio"));
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config"));
return false;
}
@@ -145,17 +169,17 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.print();
if (!std::filesystem::exists("/tmp/hyprpm")) {
std::filesystem::create_directory("/tmp/hyprpm");
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
} else if (!std::filesystem::is_directory("/tmp/hyprpm")) {
if (!std::filesystem::exists(getTempRoot())) {
std::filesystem::create_directory(getTempRoot());
std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace);
} else if (!std::filesystem::is_directory(getTempRoot())) {
std::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm"));
return false;
}
const std::string USERNAME = getpwuid(getuid())->pw_name;
m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
m_szWorkingPluginDirectory = getTempRoot() + USERNAME;
if (!createSafeDirectory(m_szWorkingPluginDirectory)) {
std::println(stderr, "\n{}", failureString("Could not prepare working dir for repo"));
@@ -164,7 +188,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.printMessageAbove(infoString("Cloning {}", url));
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME);
std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), url, USERNAME));
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret));
@@ -275,7 +299,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
}
if (m_bVerbose)
std::println("{}", verboseString("shell returned: " + out));
std::println("{}", verboseString("shell returned: {}", out));
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) {
progress.printMessageAbove(failureString("Plugin {} failed to build.\n"
@@ -347,7 +371,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
}
eHeadersErrors CPluginManager::headersValid() {
const auto HLVER = getHyprlandVersion();
const auto HLVER = getHyprlandVersion(false);
if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc"))
return HEADERS_MISSING;
@@ -409,16 +433,16 @@ bool CPluginManager::updateHeaders(bool force) {
DataState::ensureStateStoreExists();
const auto HLVER = getHyprlandVersion();
const auto HLVER = getHyprlandVersion(false);
if (!hasDeps()) {
std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio"));
std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config"));
return false;
}
if (!std::filesystem::exists("/tmp/hyprpm")) {
std::filesystem::create_directory("/tmp/hyprpm");
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
if (!std::filesystem::exists(getTempRoot())) {
std::filesystem::create_directory(getTempRoot());
std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace);
}
if (!force && headersValid() == HEADERS_OK) {
@@ -433,7 +457,7 @@ bool CPluginManager::updateHeaders(bool force) {
progress.print();
const std::string USERNAME = getpwuid(getuid())->pw_name;
const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME;
const auto WORKINGDIR = getTempRoot() + "hyprland-" + USERNAME;
if (!createSafeDirectory(WORKINGDIR)) {
std::println("\n{}", failureString("Could not prepare working dir for hl"));
@@ -451,12 +475,12 @@ bool CPluginManager::updateHeaders(bool force) {
if (m_bVerbose && bShallow)
progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE));
std::string ret =
execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""));
std::string ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-{}{}", getTempRoot(), USERNAME,
(bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")));
if (!std::filesystem::exists(WORKINGDIR)) {
progress.printMessageAbove(failureString("Clone failed. Retrying without shallow."));
ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME);
ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/hyprland hyprland-{}", getTempRoot(), USERNAME));
}
if (!std::filesystem::exists(WORKINGDIR + "/.git")) {
@@ -571,7 +595,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
return true;
}
const auto HLVER = getHyprlandVersion();
const auto HLVER = getHyprlandVersion(false);
CProgressBar progress;
progress.m_iMaxSteps = REPOS.size() * 2 + 2;
@@ -580,7 +604,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.print();
const std::string USERNAME = getpwuid(getuid())->pw_name;
m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
m_szWorkingPluginDirectory = getTempRoot() + USERNAME;
for (auto const& repo : REPOS) {
bool update = forceUpdateAll;
@@ -595,7 +619,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(infoString("Cloning {}", repo.url));
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME);
std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), repo.url, USERNAME));
if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) {
std::println("{}", failureString("could not clone repo: shell returned: {}", ret));
@@ -820,12 +844,20 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
return "";
};
// if any of the loadUnloadPlugin calls return false, this is true
// bcs that means the header version doesn't match the running version
// (and Hyprland needs to restart)
bool hyprlandVersionMismatch = false;
// unload disabled plugins
for (auto const& p : loadedPlugins) {
if (!enabled(p)) {
// unload
loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false);
std::println("{}", successString("Unloaded {}", p));
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false)) {
std::println("{}", infoString("{} will be unloaded after restarting Hyprland", p));
hyprlandVersionMismatch = true;
} else
std::println("{}", successString("Unloaded {}", p));
}
}
@@ -838,17 +870,28 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
if (std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&](const auto& other) { return other == p.name; }) != loadedPlugins.end())
continue;
loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true);
std::println("{}", successString("Loaded {}", p.name));
if (!loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true)) {
std::println("{}", infoString("{} will be loaded after restarting Hyprland", p.name));
hyprlandVersionMismatch = true;
} else
std::println("{}", successString("Loaded {}", p.name));
}
}
std::println("{}", successString("Plugin load state ensured"));
return LOADSTATE_OK;
return hyprlandVersionMismatch ? LOADSTATE_HYPRLAND_UPDATED : LOADSTATE_OK;
}
bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
auto state = DataState::getGlobalState();
auto HLVER = getHyprlandVersion(true);
if (state.headersHashCompiled != HLVER.hash) {
std::println("{}", infoString("Running Hyprland version differs from plugin state, please restart Hyprland."));
return false;
}
if (load)
execAndGet("hyprctl plugin load " + path);
else

View File

@@ -27,7 +27,8 @@ enum ePluginLoadStateReturn {
LOADSTATE_OK = 0,
LOADSTATE_FAIL,
LOADSTATE_PARTIAL_FAIL,
LOADSTATE_HEADERS_OUTDATED
LOADSTATE_HEADERS_OUTDATED,
LOADSTATE_HYPRLAND_UPDATED
};
struct SHyprlandVersion {
@@ -53,7 +54,7 @@ class CPluginManager {
ePluginLoadStateReturn ensurePluginsLoadState();
bool loadUnloadPlugin(const std::string& path, bool load);
SHyprlandVersion getHyprlandVersion();
SHyprlandVersion getHyprlandVersion(bool running = true);
void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message);

View File

@@ -73,7 +73,7 @@ int main(int argc, char** argv, char** envp) {
if (command.empty()) {
std::println(stderr, "{}", HELP);
return 0;
return 1;
}
g_pPluginManager = std::make_unique<CPluginManager>();
@@ -103,7 +103,7 @@ int main(int argc, char** argv, char** envp) {
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
bool headers = g_pPluginManager->updateHeaders(force);
if (headers) {
const auto HLVER = g_pPluginManager->getHyprlandVersion();
const auto HLVER = g_pPluginManager->getHyprlandVersion(false);
auto GLOBALSTATE = DataState::getGlobalState();
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
@@ -114,6 +114,9 @@ int main(int argc, char** argv, char** envp) {
auto ret2 = g_pPluginManager->ensurePluginsLoadState();
if (ret2 == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Updated plugins, but Hyprland was updated. Please restart Hyprland.");
if (ret2 != LOADSTATE_OK)
return 1;
} else if (notify)
@@ -130,6 +133,10 @@ int main(int argc, char** argv, char** envp) {
}
auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland.");
if (ret != LOADSTATE_OK)
return 1;
} else if (command[0] == "disable") {
@@ -158,6 +165,7 @@ int main(int argc, char** argv, char** envp) {
break;
default: break;
}
return 1;
} else if (notify && !notifyFail) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
}

View File

@@ -31,8 +31,16 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif
aquamarine = dependency('aquamarine', version: '>=0.4.2')
aquamarine = dependency('aquamarine', version: '>=0.4.5')
hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
hyprlang = dependency('hyprlang', version: '>= 0.3.2')
hyprutils = dependency('hyprutils', version: '>= 0.2.3')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp')
add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp')
add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp')
add_project_arguments(['-DHYPRUTILS_VERSION="@0@"'.format(hyprutils.version())], language: 'cpp')
xcb_dep = dependency('xcb', required: get_option('xwayland'))
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
@@ -51,9 +59,15 @@ endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs
re2 = dependency('re2', required: true)
# Handle options
if get_option('systemd').enabled()
systemd = dependency('systemd')
systemd_option = get_option('systemd')
systemd = dependency('systemd', required: systemd_option)
systemd_option.enable_auto_if(systemd.found())
if (systemd_option.enabled())
message('Enabling systemd integration')
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
subdir('systemd')
endif

View File

@@ -1,4 +1,5 @@
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration')
option('uwsm', type: 'feature', value: 'enabled', description: 'Enable uwsm integration (only if systemd is enabled)')
option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer')
option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling')

View File

@@ -12,7 +12,9 @@
cairo,
git,
hyprcursor,
hyprgraphics,
hyprland-protocols,
hyprland-qtutils,
hyprlang,
hyprutils,
hyprwayland-scanner,
@@ -25,6 +27,7 @@
mesa,
pango,
pciutils,
re2,
systemd,
tomlplusplus,
udis86-hyprland,
@@ -64,7 +67,7 @@ in
assert assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
assert assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
assert assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
customStdenv.mkDerivation {
customStdenv.mkDerivation (finalAttrs: {
pname = "hyprland${optionalString debug "-debug"}";
inherit version;
@@ -88,6 +91,7 @@ in
DATE = date;
DIRTY = optionalString (commit == "") "dirty";
HASH = commit;
TAG = "v${builtins.readFile "${finalAttrs.src}/VERSION"}";
depsBuildBuild = [
pkg-config
@@ -113,6 +117,7 @@ in
cairo
git
hyprcursor
hyprgraphics
hyprland-protocols
hyprlang
hyprutils
@@ -124,6 +129,7 @@ in
mesa
pango
pciutils
re2
tomlplusplus
udis86-hyprland
wayland
@@ -152,7 +158,7 @@ in
(mapAttrsToList mesonEnable {
"xwayland" = enableXWayland;
"legacy_renderer" = legacyRenderer;
"systemd" = withSystemd;
"uwsm" = false;
})
(mapAttrsToList mesonBool {
"b_pch" = false;
@@ -165,6 +171,7 @@ in
wrapProgram $out/bin/Hyprland \
--suffix PATH : ${makeBinPath [
binutils
hyprland-qtutils
pciutils
pkgconf
]}
@@ -180,4 +187,4 @@ in
platforms = lib.platforms.linux;
mainProgram = "Hyprland";
};
}
})

View File

@@ -22,7 +22,9 @@ in {
# Dependencies
inputs.aquamarine.overlays.default
inputs.hyprcursor.overlays.default
inputs.hyprgraphics.overlays.default
inputs.hyprland-protocols.overlays.default
inputs.hyprland-qtutils.overlays.default
inputs.hyprlang.overlays.default
inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default

View File

@@ -1,3 +1,5 @@
#include <re2/re2.h>
#include "Compositor.hpp"
#include "debug/Log.hpp"
#include "helpers/Splashes.hpp"
@@ -6,6 +8,7 @@
#include "managers/TokenManager.hpp"
#include "managers/PointerManager.hpp"
#include "managers/SeatManager.hpp"
#include "managers/VersionKeeperManager.hpp"
#include "managers/eventLoop/EventLoopManager.hpp"
#include <aquamarine/output/Output.hpp>
#include <bit>
@@ -75,7 +78,7 @@ void handleUnrecoverableSignal(int sig) {
});
alarm(15);
CrashReporter::createAndSaveCrash(sig);
NCrashReporter::createAndSaveCrash(sig);
abort();
}
@@ -87,7 +90,7 @@ void handleUserSignal(int sig) {
}
}
static LogLevel aqLevelToHl(Aquamarine::eBackendLogLevel level) {
static eLogLevel aqLevelToHl(Aquamarine::eBackendLogLevel level) {
switch (level) {
case Aquamarine::eBackendLogLevel::AQ_LOG_TRACE: return TRACE;
case Aquamarine::eBackendLogLevel::AQ_LOG_DEBUG: return LOG;
@@ -135,9 +138,7 @@ void CCompositor::restoreNofile() {
Debug::log(ERR, "Failed restoring NOFILE limits");
}
CCompositor::CCompositor() {
m_iHyprlandPID = getpid();
CCompositor::CCompositor() : m_iHyprlandPID(getpid()) {
m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr";
if (m_szHyprTempDataRoot.starts_with("/hypr")) {
@@ -152,7 +153,7 @@ CCompositor::CCompositor() {
std::mt19937 engine(dev());
std::uniform_int_distribution<> distribution(0, INT32_MAX);
m_szInstanceSignature = std::format("{}_{}_{}", GIT_COMMIT_HASH, std::time(NULL), distribution(engine));
m_szInstanceSignature = std::format("{}_{}_{}", GIT_COMMIT_HASH, std::time(nullptr), distribution(engine));
setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true);
@@ -206,11 +207,21 @@ CCompositor::~CCompositor() {
}
void CCompositor::setRandomSplash() {
auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto local = *localtime(&tt);
const auto* SPLASHES = &NSplashes::SPLASHES;
if (local.tm_mon + 1 == 12 && local.tm_mday >= 23 && local.tm_mday <= 27) // dec 23-27
SPLASHES = &NSplashes::SPLASHES_CHRISTMAS;
if ((local.tm_mon + 1 == 12 && local.tm_mday >= 29) || (local.tm_mon + 1 == 1 && local.tm_mday <= 3))
SPLASHES = &NSplashes::SPLASHES_NEWYEAR;
std::random_device dev;
std::mt19937 engine(dev());
std::uniform_int_distribution<> distribution(0, SPLASHES.size() - 1);
std::uniform_int_distribution<> distribution(0, SPLASHES->size() - 1);
m_szCurrentSplash = SPLASHES[distribution(engine)];
m_szCurrentSplash = SPLASHES->at(distribution(engine));
}
static std::vector<SP<Aquamarine::IOutput>> pendingOutputs;
@@ -250,7 +261,7 @@ void CCompositor::initServer(std::string socketName, int socketFd) {
// set the buffer size to 1MB to avoid disconnects due to an app hanging for a short while
wl_display_set_default_max_buffer_size(m_sWLDisplay, 1_MB);
Aquamarine::SBackendOptions options;
Aquamarine::SBackendOptions options{};
options.logFunction = aqLog;
std::vector<Aquamarine::SBackendImplementationOptions> implementations;
@@ -482,8 +493,8 @@ void CCompositor::cleanup() {
Debug::shuttingDown = true;
#ifdef USES_SYSTEMD
if (Systemd::SdBooted() > 0 && !envEnabled("HYPRLAND_NO_SD_NOTIFY"))
Systemd::SdNotify(0, "STOPPING=1");
if (NSystemd::sdBooted() > 0 && !envEnabled("HYPRLAND_NO_SD_NOTIFY"))
NSystemd::sdNotify(0, "STOPPING=1");
#endif
cleanEnvironment();
@@ -635,6 +646,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the CursorManager!");
g_pCursorManager = std::make_unique<CCursorManager>();
Debug::log(LOG, "Creating the VersionKeeper!");
g_pVersionKeeperMgr = std::make_unique<CVersionKeeperManager>();
Debug::log(LOG, "Starting XWayland");
g_pXWayland = std::make_unique<CXWayland>(g_pCompositor->m_bEnableXwayland);
} break;
@@ -701,10 +715,10 @@ void CCompositor::startCompositor() {
g_pHyprRenderer->setCursorFromName("left_ptr");
#ifdef USES_SYSTEMD
if (Systemd::SdBooted() > 0) {
if (NSystemd::sdBooted() > 0) {
// tell systemd that we are ready so it can start other bond, following, related units
if (!envEnabled("HYPRLAND_NO_SD_NOTIFY"))
Systemd::SdNotify(0, "READY=1");
NSystemd::sdNotify(0, "READY=1");
} else
Debug::log(LOG, "systemd integration is baked in but system itself is not booted à la systemd!");
#endif
@@ -833,6 +847,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (special && !w->onSpecialWorkspace()) // because special floating may creep up into regular
continue;
if (!w->m_pWorkspace)
continue;
const auto PWINDOWMONITOR = w->m_pMonitor.lock();
// to avoid focusing windows behind special workspaces from other monitors
@@ -844,7 +861,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
continue;
}
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() &&
if (w->m_bIsFloating && w->m_bIsMapped && w->m_pWorkspace->isVisible() && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() &&
w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
// OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && !w->isX11OverrideRedirect())
@@ -887,7 +904,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
const auto PWORKSPACE = getWorkspaceByID(WSPID);
if (PWORKSPACE->m_bHasFullscreenWindow)
return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
return PWORKSPACE->getFullscreenWindow();
auto found = floating(false);
if (found)
@@ -898,6 +915,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (special != w->onSpecialWorkspace())
continue;
if (!w->m_pWorkspace)
continue;
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) {
if (w->hasPopupAt(pos))
@@ -909,6 +929,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (special != w->onSpecialWorkspace())
continue;
if (!w->m_pWorkspace)
continue;
if (!w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() &&
w != pIgnoreWindow) {
CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize};
@@ -1070,14 +1093,15 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface
const auto PMONITOR = pWindow->m_pMonitor.lock();
if (!isWorkspaceVisible(pWindow->m_pWorkspace)) {
if (!pWindow->m_pWorkspace || !pWindow->m_pWorkspace->isVisible()) {
const auto PWORKSPACE = pWindow->m_pWorkspace;
// This is to fix incorrect feedback on the focus history.
PWORKSPACE->m_pLastFocusedWindow = pWindow;
PWORKSPACE->rememberPrevWorkspace(m_pLastMonitor->activeWorkspace);
if (m_pLastMonitor->activeWorkspace)
PWORKSPACE->rememberPrevWorkspace(m_pLastMonitor->activeWorkspace);
if (PWORKSPACE->m_bIsSpecialWorkspace)
m_pLastMonitor->changeWorkspace(PWORKSPACE, false, true); // if special ws, open on current monitor
else
else if (PMONITOR)
PMONITOR->changeWorkspace(PWORKSPACE, false, true);
// changeworkspace already calls focusWindow
return;
@@ -1088,7 +1112,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface
/* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which
window focuses are "via keybinds" and which ones aren't. */
if (PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace != pWindow->m_pWorkspace && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH)
if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace != pWindow->m_pWorkspace && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH)
PMONITOR->setSpecialWorkspace(nullptr);
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
@@ -1247,30 +1271,6 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) {
return nullptr;
}
PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const WORKSPACEID& ID) {
for (auto const& w : m_vWindows) {
if (w->workspaceID() == ID && w->isFullscreen())
return w;
}
return nullptr;
}
bool CCompositor::isWorkspaceVisible(PHLWORKSPACE w) {
return valid(w) && w->m_bVisible;
}
bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) {
if (!valid(w))
return false;
const auto PMONITOR = w->m_pMonitor.lock();
if (PMONITOR->activeSpecialWorkspace)
return PMONITOR->activeSpecialWorkspace->m_iID == w->m_iID;
return PMONITOR->activeWorkspace->m_iID == w->m_iID;
}
PHLWORKSPACE CCompositor::getWorkspaceByID(const WORKSPACEID& id) {
for (auto const& w : m_vWorkspaces) {
if (w->m_iID == id && !w->inert())
@@ -1295,37 +1295,6 @@ void CCompositor::sanityCheckWorkspaces() {
}
}
int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : m_vWindows) {
if (w->workspaceID() != id || !w->m_bIsMapped)
continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
}
return no;
}
int CCompositor::getGroupsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : m_vWindows) {
if (w->workspaceID() != id || !w->m_bIsMapped)
continue;
if (!w->m_sGroupData.head)
continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
}
return no;
}
PHLWINDOW CCompositor::getUrgentWindow() {
for (auto const& w : m_vWindows) {
if (w->m_bIsMapped && w->m_bIsUrgent)
@@ -1335,44 +1304,6 @@ PHLWINDOW CCompositor::getUrgentWindow() {
return nullptr;
}
bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) {
for (auto const& w : m_vWindows) {
if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent)
return true;
}
return false;
}
PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const WORKSPACEID& id) {
for (auto const& w : m_vWindows) {
if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden())
return w;
}
return nullptr;
}
PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) {
const auto PWORKSPACE = getWorkspaceByID(id);
if (!PWORKSPACE)
return nullptr;
const auto PMONITOR = PWORKSPACE->m_pMonitor.lock();
for (auto const& w : m_vWindows) {
if (w->workspaceID() != id || !w->m_bIsMapped || w->isHidden())
continue;
const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
if (WINDOWIDEALBB.x <= PMONITOR->vecPosition.x + 1 && WINDOWIDEALBB.y <= PMONITOR->vecPosition.y + 1)
return w;
}
return nullptr;
}
bool CCompositor::isWindowActive(PHLWINDOW pWindow) {
if (m_pLastWindow.expired() && !m_pLastFocus)
return false;
@@ -1389,6 +1320,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
if (!validMapped(pWindow))
return;
if (top)
pWindow->m_bCreatedOverFullscreen = true;
if (pWindow == (top ? m_vWindows.back() : m_vWindows.front()))
return;
@@ -1413,24 +1347,21 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
g_pHyprRenderer->damageMonitor(pw->m_pMonitor.lock());
};
if (top)
pWindow->m_bCreatedOverFullscreen = true;
if (!pWindow->m_bIsX11)
moveToZ(pWindow, top);
else {
// move X11 window stack
std::deque<PHLWINDOW> toMove;
std::vector<PHLWINDOW> toMove;
auto x11Stack = [&](PHLWINDOW pw, bool top, auto&& x11Stack) -> void {
auto x11Stack = [&](PHLWINDOW pw, bool top, auto&& x11Stack) -> void {
if (top)
toMove.emplace_back(pw);
else
toMove.emplace_front(pw);
toMove.insert(toMove.begin(), pw);
for (auto const& w : m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->x11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) {
x11Stack(w, top, x11Stack);
}
}
@@ -1438,7 +1369,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
x11Stack(pWindow, top, x11Stack);
for (auto it : toMove) {
for (const auto& it : toMove) {
moveToZ(it, top);
}
}
@@ -1560,7 +1491,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
// for tiled windows, we calc edges
for (auto const& w : m_vWindows) {
if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace))
if (w == pWindow || !w->m_pWorkspace || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !w->m_pWorkspace->isVisible())
continue;
if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace)
@@ -1642,7 +1573,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
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 {
auto vectorAngles = [](const Vector2D& a, const Vector2D& b) -> double {
double dot = a.x * b.x + a.y * b.y;
double ang = std::acos(dot / (a.size() * b.size()));
return ang;
@@ -1652,7 +1583,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
constexpr float THRESHOLD = 0.3 * M_PI;
for (auto const& w : m_vWindows) {
if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace))
if (w == pWindow || !w->m_bIsMapped || !w->m_pWorkspace || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !w->m_pWorkspace->isVisible())
continue;
if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace)
@@ -1678,7 +1609,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
}
if (!leaderWindow && PWORKSPACE->m_bHasFullscreenWindow)
leaderWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
leaderWindow = PWORKSPACE->getFullscreenWindow();
}
if (leaderValue != -1)
@@ -1871,15 +1802,6 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() {
}
}
void CCompositor::updateWorkspaceWindows(const int64_t& id) {
for (auto const& w : m_vWindows) {
if (!w->m_bIsMapped || w->workspaceID() != id)
continue;
w->updateDynamicRules();
}
}
void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
// optimization
static auto PACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.active_border");
@@ -1966,11 +1888,11 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) {
// shadow
if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) {
if (pWindow == m_pLastWindow)
pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL);
pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOL);
else
pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL);
} else {
pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow
pWindow->m_cRealShadowColor.setValueAndWarp(CHyprColor(0, 0, 0, 0)); // no shadow
}
pWindow->updateWindowDecos();
@@ -2325,20 +2247,21 @@ void CCompositor::changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, cons
void CCompositor::setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE) {
if (PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = MODE, .client = MODE});
setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = MODE, .client = MODE});
else
setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = MODE, .client = PWINDOW->m_sFullscreenState.client});
setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = MODE, .client = PWINDOW->m_sFullscreenState.client});
}
void CCompositor::setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE) {
if (PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = MODE, .client = MODE});
setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = MODE, .client = MODE});
else
setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = MODE});
setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = MODE});
}
void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenState state) {
static auto PDIRECTSCANOUT = CConfigValue<Hyprlang::INT>("render:direct_scanout");
void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenState state) {
static auto PDIRECTSCANOUT = CConfigValue<Hyprlang::INT>("render:direct_scanout");
static auto PALLOWPINFULLSCREEN = CConfigValue<Hyprlang::INT>("binds:allow_pin_fullscreen");
if (!validMapped(PWINDOW) || g_pCompositor->m_bUnsafeState)
return;
@@ -2352,7 +2275,20 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS
const eFullscreenMode CURRENT_EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)PWINDOW->m_sFullscreenState.internal);
const eFullscreenMode EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)state.internal);
const bool CHANGEINTERNAL = !(PWINDOW->m_bPinned || CURRENT_EFFECTIVE_MODE == EFFECTIVE_MODE || (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen()));
if (*PALLOWPINFULLSCREEN && !PWINDOW->m_bPinFullscreened && !PWINDOW->isFullscreen() && PWINDOW->m_bPinned) {
PWINDOW->m_bPinned = false;
PWINDOW->m_bPinFullscreened = true;
}
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen())
setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE);
const bool CHANGEINTERNAL = !(PWINDOW->m_bPinned || CURRENT_EFFECTIVE_MODE == EFFECTIVE_MODE);
if (*PALLOWPINFULLSCREEN && PWINDOW->m_bPinFullscreened && PWINDOW->isFullscreen() && !PWINDOW->m_bPinned && state.internal == FSMODE_NONE) {
PWINDOW->m_bPinned = true;
PWINDOW->m_bPinFullscreened = false;
}
// TODO: update the state on syncFullscreen changes
if (!CHANGEINTERNAL && PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
@@ -2391,7 +2327,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
forceReportSizesToWindowsOnWorkspace(PWINDOW->workspaceID());
PWORKSPACE->forceReportSizesToWindows();
g_pInputManager->recheckIdleInhibitorStatus();
@@ -2422,27 +2358,6 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) {
return nullptr;
}
void CCompositor::updateWorkspaceWindowDecos(const WORKSPACEID& id) {
for (auto const& w : m_vWindows) {
if (w->workspaceID() != id)
continue;
w->updateWindowDecos();
}
}
void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) {
const auto PWORKSPACE = getWorkspaceByID(id);
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
for (auto const& w : m_vWindows) {
if (w->workspaceID() != id)
continue;
w->updateWindowData(WORKSPACERULE);
}
}
void CCompositor::scheduleFrameForMonitor(PHLMONITOR pMonitor, IOutput::scheduleFrameReason reason) {
if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive)
return;
@@ -2480,19 +2395,19 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp_) {
eFocusWindowMode mode = MODE_CLASS_REGEX;
std::regex regexCheck(regexp_);
std::string regexCheck;
std::string matchCheck;
if (regexp.starts_with("class:")) {
regexCheck = std::regex(regexp.substr(6));
regexCheck = regexp.substr(6);
} else if (regexp.starts_with("initialclass:")) {
mode = MODE_INITIAL_CLASS_REGEX;
regexCheck = std::regex(regexp.substr(13));
regexCheck = regexp.substr(13);
} else if (regexp.starts_with("title:")) {
mode = MODE_TITLE_REGEX;
regexCheck = std::regex(regexp.substr(6));
regexCheck = regexp.substr(6);
} else if (regexp.starts_with("initialtitle:")) {
mode = MODE_INITIAL_TITLE_REGEX;
regexCheck = std::regex(regexp.substr(13));
regexCheck = regexp.substr(13);
} else if (regexp.starts_with("address:")) {
mode = MODE_ADDRESS;
matchCheck = regexp.substr(8);
@@ -2508,25 +2423,25 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp_) {
switch (mode) {
case MODE_CLASS_REGEX: {
const auto windowClass = w->m_szClass;
if (!std::regex_search(windowClass, regexCheck))
if (!RE2::FullMatch(windowClass, regexCheck))
continue;
break;
}
case MODE_INITIAL_CLASS_REGEX: {
const auto initialWindowClass = w->m_szInitialClass;
if (!std::regex_search(initialWindowClass, regexCheck))
if (!RE2::FullMatch(initialWindowClass, regexCheck))
continue;
break;
}
case MODE_TITLE_REGEX: {
const auto windowTitle = w->m_szTitle;
if (!std::regex_search(windowTitle, regexCheck))
if (!RE2::FullMatch(windowTitle, regexCheck))
continue;
break;
}
case MODE_INITIAL_TITLE_REGEX: {
const auto initialWindowTitle = w->m_szInitialTitle;
if (!std::regex_search(initialWindowTitle, regexCheck))
if (!RE2::FullMatch(initialWindowTitle, regexCheck))
continue;
break;
}
@@ -2654,16 +2569,8 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
return Vector2D(X, Y);
}
void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) {
for (auto const& w : m_vWindows) {
if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) {
g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true);
}
}
}
PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmpty) {
const auto NAME = name == "" ? std::to_string(id) : name;
const auto NAME = name.empty() ? std::to_string(id) : name;
auto monID = monid;
// check if bound
@@ -2679,21 +2586,6 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO
return PWORKSPACE;
}
void CCompositor::renameWorkspace(const WORKSPACEID& id, const std::string& name) {
const auto PWORKSPACE = getWorkspaceByID(id);
if (!PWORKSPACE)
return;
if (isWorkspaceSpecial(id))
return;
Debug::log(LOG, "renameWorkspace: Renaming workspace {} to '{}'", id, name);
PWORKSPACE->m_szName = name;
g_pEventManager->postEvent({"renameworkspace", std::to_string(PWORKSPACE->m_iID) + "," + PWORKSPACE->m_szName});
}
void CCompositor::setActiveMonitor(PHLMONITOR pMonitor) {
if (m_pLastMonitor == pMonitor)
return;
@@ -2726,7 +2618,8 @@ WORKSPACEID CCompositor::getNewSpecialID() {
}
void CCompositor::performUserChecks() {
static auto PNOCHECKXDG = CConfigValue<Hyprlang::INT>("misc:disable_xdg_env_checks");
static auto PNOCHECKXDG = CConfigValue<Hyprlang::INT>("misc:disable_xdg_env_checks");
static auto PNOCHECKQTUTILS = CConfigValue<Hyprlang::INT>("misc:disable_hyprland_qtutils_check");
if (!*PNOCHECKXDG) {
const auto CURRENT_DESKTOP_ENV = getenv("XDG_CURRENT_DESKTOP");
@@ -2734,14 +2627,21 @@ void CCompositor::performUserChecks() {
g_pHyprNotificationOverlay->addNotification(
std::format("Your XDG_CURRENT_DESKTOP environment seems to be managed externally, and the current value is {}.\nThis might cause issues unless it's intentional.",
CURRENT_DESKTOP_ENV ? CURRENT_DESKTOP_ENV : "unset"),
CColor{}, 15000, ICON_WARNING);
CHyprColor{}, 15000, ICON_WARNING);
}
}
if (!*PNOCHECKQTUTILS) {
if (!executableExistsInPath("hyprland-dialog")) {
g_pHyprNotificationOverlay->addNotification(
"Your system does not have hyprland-qtutils installed. This is a runtime dependency for some dialogs. Consider installing it.", CHyprColor{}, 15000, ICON_WARNING);
}
}
if (g_pHyprOpenGL->failedAssetsNo > 0) {
g_pHyprNotificationOverlay->addNotification(std::format("Hyprland failed to load {} essential asset{}, blame your distro's packager for doing a bad job at packaging!",
g_pHyprOpenGL->failedAssetsNo, g_pHyprOpenGL->failedAssetsNo > 1 ? "s" : ""),
CColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR);
CHyprColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR);
}
}
@@ -2758,8 +2658,8 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor
if (FULLSCREEN)
setWindowFullscreenInternal(pWindow, FSMODE_NONE);
const PHLWINDOW pFirstWindowOnWorkspace = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
const int visibleWindowsOnWorkspace = g_pCompositor->getWindowsOnWorkspace(pWorkspace->m_iID, std::nullopt, true);
const PHLWINDOW pFirstWindowOnWorkspace = pWorkspace->getFirstWindow();
const int visibleWindowsOnWorkspace = pWorkspace->getWindows(std::nullopt, true);
const auto PWINDOWMONITOR = pWindow->m_pMonitor.lock();
const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition;
const auto PWORKSPACEMONITOR = pWorkspace->m_pMonitor.lock();
@@ -2817,14 +2717,15 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor
if (FULLSCREEN)
setWindowFullscreenInternal(pWindow, FULLSCREENMODE);
g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID);
g_pCompositor->updateWorkspaceWindows(pWindow->workspaceID());
pWorkspace->updateWindows();
if (pWindow->m_pWorkspace)
pWindow->m_pWorkspace->updateWindows();
g_pCompositor->updateSuspendedStates();
}
PHLWINDOW CCompositor::getForceFocus() {
for (auto const& w : m_vWindows) {
if (!w->m_bIsMapped || w->isHidden() || !isWorkspaceVisible(w->m_pWorkspace))
if (!w->m_bIsMapped || w->isHidden() || !w->m_pWorkspace || !w->m_pWorkspace->isVisible())
continue;
if (!w->m_bStayFocused)
@@ -2868,50 +2769,48 @@ void CCompositor::arrangeMonitors() {
}
// Variables to store the max and min values of monitors on each axis.
int maxXOffsetRight = 0;
int maxXOffsetLeft = 0;
int maxYOffsetUp = 0;
int maxYOffsetDown = 0;
int maxXOffsetRight = 0;
int maxXOffsetLeft = 0;
int maxYOffsetUp = 0;
int maxYOffsetDown = 0;
// Finds the max and min values of explicitely placed monitors.
for (auto const& m : arranged) {
if (m->vecPosition.x + m->vecSize.x > maxXOffsetRight)
maxXOffsetRight = m->vecPosition.x + m->vecSize.x;
if (m->vecPosition.x < maxXOffsetLeft)
maxXOffsetLeft = m->vecPosition.x;
if (m->vecPosition.y + m->vecSize.y > maxYOffsetDown)
maxYOffsetDown = m->vecPosition.y + m->vecSize.y;
if (m->vecPosition.y < maxYOffsetUp)
maxYOffsetUp = m->vecPosition.y;
}
auto recalcMaxOffsets = [&]() {
maxXOffsetRight = 0;
maxXOffsetLeft = 0;
maxYOffsetUp = 0;
maxYOffsetDown = 0;
// Finds the max and min values of explicitely placed monitors.
for (auto const& m : arranged) {
if (m->vecPosition.x + m->vecSize.x > maxXOffsetRight)
maxXOffsetRight = m->vecPosition.x + m->vecSize.x;
if (m->vecPosition.x < maxXOffsetLeft)
maxXOffsetLeft = m->vecPosition.x;
if (m->vecPosition.y + m->vecSize.y > maxYOffsetDown)
maxYOffsetDown = m->vecPosition.y + m->vecSize.y;
if (m->vecPosition.y < maxYOffsetUp)
maxYOffsetUp = m->vecPosition.y;
}
};
// Iterates through all non-explicitly placed monitors.
for (auto const& m : toArrange) {
recalcMaxOffsets();
// Moves the monitor to their appropriate position on the x/y axis and
// increments/decrements the corresponding max offset.
Vector2D newPosition = {0, 0};
switch (m->activeMonitorRule.autoDir) {
case eAutoDirs::DIR_AUTO_UP:
newPosition.y = maxYOffsetUp - m->vecSize.y;
maxYOffsetUp = newPosition.y;
break;
case eAutoDirs::DIR_AUTO_DOWN:
newPosition.y = maxYOffsetDown;
maxYOffsetDown += m->vecSize.y;
break;
case eAutoDirs::DIR_AUTO_LEFT:
newPosition.x = maxXOffsetLeft - m->vecSize.x;
maxXOffsetLeft = newPosition.x;
break;
case eAutoDirs::DIR_AUTO_UP: newPosition.y = maxYOffsetUp - m->vecSize.y; break;
case eAutoDirs::DIR_AUTO_DOWN: newPosition.y = maxYOffsetDown; break;
case eAutoDirs::DIR_AUTO_LEFT: newPosition.x = maxXOffsetLeft - m->vecSize.x; break;
case eAutoDirs::DIR_AUTO_RIGHT:
case eAutoDirs::DIR_AUTO_NONE:
newPosition.x = maxXOffsetRight;
maxXOffsetRight += m->vecSize.x;
break;
case eAutoDirs::DIR_AUTO_NONE: newPosition.x = maxXOffsetRight; break;
default: UNREACHABLE();
}
Debug::log(LOG, "arrangeMonitors: {} auto {:j}", m->szName, m->vecPosition);
m->moveTo(newPosition);
arranged.emplace_back(m);
}
// reset maxXOffsetRight (reuse)
@@ -3002,7 +2901,7 @@ void CCompositor::updateSuspendedStates() {
if (!w->m_bIsMapped)
continue;
w->setSuspended(w->isHidden() || !isWorkspaceVisible(w->m_pWorkspace));
w->setSuspended(w->isHidden() || !w->m_pWorkspace || !w->m_pWorkspace->isVisible());
}
}

View File

@@ -1,7 +1,6 @@
#pragma once
#include <memory>
#include <deque>
#include <list>
#include <sys/resource.h>
@@ -35,7 +34,7 @@
class CWLSurfaceResource;
enum eManagersInitStage {
enum eManagersInitStage : uint8_t {
STAGE_PRIORITY = 0,
STAGE_BASICINIT,
STAGE_LATE
@@ -115,21 +114,11 @@ class CCompositor {
PHLMONITOR getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE);
bool isWorkspaceVisibleNotCovered(PHLWORKSPACE);
PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&);
PHLWORKSPACE getWorkspaceByName(const std::string&);
PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const WORKSPACEID&);
void updateWorkspaceWindowData(const WORKSPACEID&);
int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
PHLWINDOW getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&);
bool isWindowActive(PHLWINDOW);
void changeWindowZOrder(PHLWINDOW, bool);
void cleanupFadingOut(const MONITORID& monid);
@@ -142,7 +131,6 @@ class CCompositor {
PHLMONITOR getMonitorInDirection(const char&);
PHLMONITOR getMonitorInDirection(PHLMONITOR, const char&);
void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const WORKSPACEID& id);
void updateWindowAnimatedDecorationValues(PHLWINDOW);
MONITORID getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false);
@@ -151,7 +139,7 @@ class CCompositor {
bool workspaceIDOutOfBounds(const WORKSPACEID&);
void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state);
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const SFullscreenState state);
void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
@@ -165,10 +153,8 @@ class CCompositor {
PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>);
void closeWindow(PHLWINDOW);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&);
PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "",
bool isEmpty = true); // will be deleted next frame if left empty and unfocused!
void renameWorkspace(const WORKSPACEID&, const std::string& name = "");
void setActiveMonitor(PHLMONITOR);
bool isWorkspaceSpecial(const WORKSPACEID&);
WORKSPACEID getNewSpecialID();

View File

@@ -5,9 +5,7 @@
#include <any>
#include <hyprutils/math/Box.hpp>
using namespace Hyprutils::Math;
enum eIcons {
enum eIcons : uint8_t {
ICON_WARNING = 0,
ICON_INFO,
ICON_HINT,
@@ -17,7 +15,7 @@ enum eIcons {
ICON_NONE
};
enum eRenderStage {
enum eRenderStage : uint8_t {
RENDER_PRE = 0, /* Before binding the gl context */
RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */
RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */
@@ -29,7 +27,7 @@ enum eRenderStage {
RENDER_POST_WINDOW, /* After rendering a window (any pass) */
};
enum eInputType {
enum eInputType : uint8_t {
INPUT_TYPE_AXIS = 0,
INPUT_TYPE_BUTTON,
INPUT_TYPE_DRAG_START,
@@ -41,7 +39,7 @@ struct SCallbackInfo {
bool cancelled = false; /* on cancellable events, will cancel the event. */
};
enum eHyprCtlOutputFormat {
enum eHyprCtlOutputFormat : uint8_t {
FORMAT_NORMAL = 0,
FORMAT_JSON
};

View File

@@ -3,7 +3,7 @@
#include "../helpers/varlist/VarList.hpp"
#include <vector>
enum eConfigValueDataTypes {
enum eConfigValueDataTypes : int8_t {
CVD_TYPE_INVALID = -1,
CVD_TYPE_GRADIENT = 0,
CVD_TYPE_CSS_VALUE = 1
@@ -20,24 +20,40 @@ class ICustomConfigValueData {
class CGradientValueData : public ICustomConfigValueData {
public:
CGradientValueData() {};
CGradientValueData(CColor col) {
CGradientValueData() = default;
CGradientValueData(CHyprColor col) {
m_vColors.push_back(col);
updateColorsOk();
};
virtual ~CGradientValueData() {};
virtual ~CGradientValueData() = default;
virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_GRADIENT;
}
void reset(CColor col) {
void reset(CHyprColor col) {
m_vColors.clear();
m_vColors.emplace_back(col);
m_fAngle = 0;
updateColorsOk();
}
void updateColorsOk() {
m_vColorsOkLabA.clear();
for (auto& c : m_vColors) {
const auto OKLAB = c.asOkLab();
m_vColorsOkLabA.emplace_back(OKLAB.l);
m_vColorsOkLabA.emplace_back(OKLAB.a);
m_vColorsOkLabA.emplace_back(OKLAB.b);
m_vColorsOkLabA.emplace_back(c.a);
}
}
/* Vector containing the colors */
std::vector<CColor> m_vColors;
std::vector<CHyprColor> m_vColors;
/* Vector containing pure colors for shoving into opengl */
std::vector<float> m_vColorsOkLabA;
/* Float corresponding to the angle (rad) */
float m_fAngle = 0;

View File

@@ -268,7 +268,7 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.value = "blur:ignore_opacity",
.description = "make the blur layer ignore the opacity of the window",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "blur:new_optimizations",
@@ -331,6 +331,18 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
},
SConfigOptionDescription{
.value = "blur:input_methods",
.description = "whether to blur input methods (e.g. fcitx5)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "blur:input_methods_ignorealpha",
.description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]",
.type = CONFIG_OPTION_FLOAT,
.data = SConfigOptionDescription::SFloatData{0.2, 0, 1},
},
/*
* animations:
@@ -620,16 +632,22 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
},
SConfigOptionDescription{
.value = "input:tablet:output",
.description = "the monitor to bind tablets. Empty means unbound..",
.description = "the monitor to bind tablets. Can be current or a monitor name. Leave empty to map across all monitors.",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
},
SConfigOptionDescription{
.value = "input:tablet:region_position",
.description = "position of the mapped region in monitor layout.",
.description = "position of the mapped region in monitor layout relative to the top left corner of the bound monitor or all monitors.",
.type = CONFIG_OPTION_VECTOR,
.data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}},
},
SConfigOptionDescription{
.value = "input:tablet:absolute_region_position",
.description = "whether to treat the region_position as an absolute position in monitor layout. Only applies when output is empty.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "input:tablet:region_size",
.description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.",
@@ -1115,6 +1133,18 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "misc:disable_hyprland_qtutils_check",
.description = "disable the warning if hyprland-qtutils is missing",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "misc:lockdead_screen_delay",
.description = "the delay in ms after the lockdead screen appears if the lock screen did not appear after a lock event occurred.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1000, 0, 5000},
},
/*
* binds:
@@ -1170,6 +1200,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "binds:movefocus_cycles_groupfirst",
.description = "If enabled, when in a grouped window, movefocus will cycle windows in the groups first, then at each ends of tabs, it'll move on to other windows/groups",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "binds:disable_keybind_grabbing",
.description = "If enabled, apps that request keybinds to be disabled (e.g. VMs) will not be able to do so.",
@@ -1182,6 +1218,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "binds:allow_pin_fullscreen",
.description = "Allows fullscreen to pinned windows, and restore their pinned status afterwards",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/*
* xwayland:
@@ -1303,9 +1345,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
},
SConfigOptionDescription{
.value = "cursor:warp_on_change_workspace",
.description = "If true, move the cursor to the last focused window after changing the workspace.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
.description = "Move the cursor to the last focused window after changing the workspace. Options: 0 (Disabled), 1 (Enabled), 2 (Force - ignores cursor:no_warps option)",
.type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"},
},
SConfigOptionDescription{
.value = "cursor:default_monitor",
@@ -1344,8 +1386,8 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "cursor:allow_dumb_copy",
.description = "Makes HW cursors work on Nvidia, at the cost of a possible hitch whenever the image changes",
.value = "cursor:use_cpu_buffer",
.description = "Makes HW cursors use a CPU buffer. Required on Nvidia to have HW cursors. Experimental",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
@@ -1566,6 +1608,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:center_ignores_reserved",
.description = "centers the master window on monitor ignoring reserved areas",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{
.value = "master:smart_resizing",
.description =

File diff suppressed because it is too large Load Diff

View File

@@ -8,9 +8,7 @@
#include "../defines.hpp"
#include <variant>
#include <vector>
#include <deque>
#include <algorithm>
#include <regex>
#include <optional>
#include <functional>
#include <xf86drmMode.h>
@@ -69,13 +67,13 @@ struct SAnimationPropertyConfig {
};
struct SPluginKeyword {
HANDLE handle = 0;
HANDLE handle = nullptr;
std::string name = "";
Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
};
struct SPluginVariable {
HANDLE handle = 0;
HANDLE handle = nullptr;
std::string name = "";
};
@@ -84,7 +82,7 @@ struct SExecRequestedRule {
uint64_t iPid = 0;
};
enum eConfigOptionType : uint16_t {
enum eConfigOptionType : uint8_t {
CONFIG_OPTION_BOOL = 0,
CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/
CONFIG_OPTION_FLOAT = 2,
@@ -96,7 +94,7 @@ enum eConfigOptionType : uint16_t {
CONFIG_OPTION_VECTOR = 8,
};
enum eConfigOptionFlags : uint32_t {
enum eConfigOptionFlags : uint8_t {
CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0),
};
@@ -119,7 +117,7 @@ struct SConfigOptionDescription {
};
struct SColorData {
CColor color;
CHyprColor color;
};
struct SChoiceData {
@@ -167,7 +165,7 @@ class CConfigManager {
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load);
static std::string getMainConfigPath();
const std::string getConfigString();
std::string getConfigString();
SMonitorRule getMonitorRuleFor(const PHLMONITOR);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
@@ -175,10 +173,10 @@ class CConfigManager {
PHLMONITOR getBoundMonitorForWS(const std::string&);
std::string getBoundMonitorStringForWS(const std::string&);
const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
const std::vector<SWorkspaceRule>& getAllWorkspaceRules();
std::vector<SWindowRule> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
std::vector<SLayerRule> getMatchingRules(PHLLS);
std::vector<SP<CWindowRule>> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
std::vector<SP<CLayerRule>> getMatchingRules(PHLLS);
const std::vector<SConfigOptionDescription>& getAllDescriptions();
@@ -214,52 +212,58 @@ class CConfigManager {
std::string getErrors();
// keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleExecShutdown(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleExecShutdown(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::string configCurrentPath;
std::string configCurrentPath;
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(PHLWINDOW)>> mbWindowProperties = {
{"allowsinput", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }},
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> mbWindowProperties = {
{"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(PHLWINDOW)>> miWindowProperties = {
{"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> miWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }},
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> mfWindowProperties = {
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}};
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
@@ -269,7 +273,7 @@ class CConfigManager {
private:
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
std::deque<std::string> configPaths; // stores all the config paths
std::vector<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
@@ -284,16 +288,16 @@ class CConfigManager {
bool isFirstLaunch = true; // For exec-once
std::deque<SMonitorRule> m_dMonitorRules;
std::deque<SWorkspaceRule> m_dWorkspaceRules;
std::deque<SWindowRule> m_dWindowRules;
std::deque<SLayerRule> m_dLayerRules;
std::deque<std::string> m_dBlurLSNamespaces;
std::vector<SMonitorRule> m_vMonitorRules;
std::vector<SWorkspaceRule> m_vWorkspaceRules;
std::vector<SP<CWindowRule>> m_vWindowRules;
std::vector<SP<CLayerRule>> m_vLayerRules;
std::vector<std::string> m_dBlurLSNamespaces;
bool firstExecDispatched = false;
bool m_bManualCrashInitiated = false;
std::deque<std::string> firstExecRequests;
std::deque<std::string> finalExecRequests;
std::vector<std::string> firstExecRequests;
std::vector<std::string> finalExecRequests;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_szConfigErrors = "";

View File

@@ -13,6 +13,7 @@ class CConfigValue {
CConfigValue(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
// NOLINTNEXTLINE
p_ = PVHYPRLANG->getDataStaticPtr();
#ifdef HYPRLAND_DEBUG

View File

@@ -4,8 +4,8 @@
inline const std::string AUTOCONFIG = R"#(
# #######################################################################################
# AUTOGENERATED HYPR CONFIG.
# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
# AUTOGENERATED HYPRLAND CONFIG.
# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hyprland.conf AND EDIT IT,
# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
# #######################################################################################
@@ -149,13 +149,10 @@ animations {
# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/
# "Smart gaps" / "No gaps when only"
# uncomment all if you wish to use that.
# workspace = w[t1], gapsout:0, gapsin:0
# workspace = w[tg1], gapsout:0, gapsin:0
# workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[t1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[t1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tg1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tg1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]

View File

@@ -2,8 +2,8 @@
#include <fcntl.h>
#include <sys/utsname.h>
#include <link.h>
#include <time.h>
#include <errno.h>
#include <ctime>
#include <cerrno>
#include <sys/stat.h>
#include <filesystem>
@@ -31,10 +31,10 @@ static char const* const MESSAGES[] = {"Sorry, didn't mean to...",
// <random> is not async-signal-safe, fake it with time(NULL) instead
char const* getRandomMessage() {
return MESSAGES[time(NULL) % (sizeof(MESSAGES) / sizeof(MESSAGES[0]))];
return MESSAGES[time(nullptr) % (sizeof(MESSAGES) / sizeof(MESSAGES[0]))];
}
[[noreturn]] inline void exit_with_error(char const* err) {
[[noreturn]] inline void exitWithError(char const* err) {
write(STDERR_FILENO, err, strlen(err));
// perror() is not signal-safe, but we use it here
// because if the crash-handler already crashed, it can't get any worse.
@@ -42,17 +42,17 @@ char const* getRandomMessage() {
abort();
}
void CrashReporter::createAndSaveCrash(int sig) {
int reportFd;
void NCrashReporter::createAndSaveCrash(int sig) {
int reportFd = -1;
// We're in the signal handler, so we *only* have stack memory.
// To save as much stack memory as possible,
// destroy things as soon as possible.
{
MaxLengthCString<255> reportPath;
CMaxLengthCString<255> reportPath;
const auto HOME = sig_getenv("HOME");
const auto CACHE_HOME = sig_getenv("XDG_CACHE_HOME");
const auto HOME = sigGetenv("HOME");
const auto CACHE_HOME = sigGetenv("XDG_CACHE_HOME");
if (CACHE_HOME && CACHE_HOME[0] != '\0') {
reportPath += CACHE_HOME;
@@ -61,24 +61,24 @@ void CrashReporter::createAndSaveCrash(int sig) {
reportPath += HOME;
reportPath += "/.cache/hyprland";
} else {
exit_with_error("$CACHE_HOME and $HOME not set, nowhere to report crash\n");
exitWithError("$CACHE_HOME and $HOME not set, nowhere to report crash\n");
return;
}
int ret = mkdir(reportPath.get_str(), S_IRWXU);
int ret = mkdir(reportPath.getStr(), S_IRWXU);
//__asm__("int $3");
if (ret < 0 && errno != EEXIST) {
exit_with_error("failed to mkdir() crash report directory\n");
exitWithError("failed to mkdir() crash report directory\n");
}
reportPath += "/hyprlandCrashReport";
reportPath.write_num(getpid());
reportPath.writeNum(getpid());
reportPath += ".txt";
{
BufFileWriter<64> stderr(2);
CBufFileWriter<64> stderr(2);
stderr += "Hyprland has crashed :( Consult the crash report at ";
if (!reportPath.boundsExceeded()) {
stderr += reportPath.get_str();
stderr += reportPath.getStr();
} else {
stderr += "[ERROR: Crash report path does not fit into memory! Check if your $CACHE_HOME/$HOME is too deeply nested. Max 255 characters.]";
}
@@ -86,12 +86,12 @@ void CrashReporter::createAndSaveCrash(int sig) {
stderr.flush();
}
reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
reportFd = open(reportPath.getStr(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (reportFd < 0) {
exit_with_error("Failed to open crash report path for writing");
exitWithError("Failed to open crash report path for writing");
}
}
BufFileWriter<512> finalCrashReport(reportFd);
CBufFileWriter<512> finalCrashReport(reportFd);
finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n";
finalCrashReport += getRandomMessage();
@@ -100,7 +100,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "Hyprland received signal ";
finalCrashReport.writeNum(sig);
finalCrashReport += '(';
finalCrashReport += sig_strsignal(sig);
finalCrashReport += sigStrsignal(sig);
finalCrashReport += ")\nVersion: ";
finalCrashReport += GIT_COMMIT_HASH;
finalCrashReport += "\nTag: ";
@@ -122,9 +122,9 @@ void CrashReporter::createAndSaveCrash(int sig) {
if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) {
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
size_t count = g_pPluginSystem->pluginCount();
CPlugin* plugins[count];
g_pPluginSystem->sig_getPlugins(plugins, count);
const size_t count = g_pPluginSystem->pluginCount();
std::vector<CPlugin*> plugins(count);
g_pPluginSystem->sigGetPlugins(plugins.data(), count);
for (size_t i = 0; i < count; i++) {
auto p = plugins[i];
@@ -159,7 +159,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "GPU:\n\t";
#if defined(__DragonFly__) || defined(__FreeBSD__)
finalCrashReport.writeCmdOutput("pciconf -lv | fgrep -A4 vga");
finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga");
#else
finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA");
#endif
@@ -241,5 +241,5 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "\n\nLog tail:\n";
finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find("\n") + 1);
finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find('\n') + 1);
}

View File

@@ -2,6 +2,6 @@
#include "../defines.hpp"
namespace CrashReporter {
namespace NCrashReporter {
void createAndSaveCrash(int sig);
};

View File

@@ -1,10 +1,13 @@
#include "HyprCtl.hpp"
#include <algorithm>
#include <format>
#include <fstream>
#include <iterator>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -36,6 +39,7 @@ using namespace Hyprutils::String;
#include "debug/RollingLogFollow.hpp"
#include "config/ConfigManager.hpp"
#include "helpers/MiscFunctions.hpp"
#include "../version.h"
static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',')
@@ -105,6 +109,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"vrr": {},
"solitary": "{:x}",
"activelyTearing": {},
"directScanoutTo": "{:x}",
"disabled": {},
"currentFormat": "{}",
"mirrorOf": "{}",
@@ -117,19 +122,20 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(),
(m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat),
m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format));
(m->tearingState.activelyTearing ? "true" : "false"), (uint64_t)m->lastScanout.get(), (m->m_bEnabled ? "false" : "true"),
formatToString(m->output->state->state().drmFormat), m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format));
} else {
result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tmirrorOf: {}\n\tavailableModes: {}\n\n",
"dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdirectScanoutTo: {:x}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tmirrorOf: "
"{}\n\tavailableModes: {}\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->szShortDescription,
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(),
m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat),
m->tearingState.activelyTearing, (uint64_t)m->lastScanout.get(), !m->m_bEnabled, formatToString(m->output->state->state().drmFormat),
m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format));
}
@@ -239,7 +245,8 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"grouped": [{}],
"tags": [{}],
"swallowing": "0x{:x}",
"focusHistoryID": {}
"focusHistoryID": {},
"inhibitingIdle": {}
}},)#",
(uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
@@ -247,18 +254,18 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
(int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass),
escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
(uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false"));
} else {
return std::format(
"Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\txwayland: {}\n\tpinned: "
"{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
"{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\tinhibitingIdle: {}\n\n",
(uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName),
(int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(),
(int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
(uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (int)g_pInputManager->isWindowInhibiting(w, false));
}
}
@@ -303,12 +310,12 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form
"lastwindowtitle": "{}"
}})#",
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.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"),
(uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "");
} else {
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.get(), PLASTW ? PLASTW->m_szTitle : "");
w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow,
(uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "");
}
}
@@ -531,7 +538,7 @@ std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request
CVarList errLines(currErrors, 0, '\n');
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto line : errLines) {
for (const auto& line : errLines) {
result += std::format(
R"#(
"{}",)#",
@@ -541,7 +548,7 @@ std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request
trimTrailingComma(result);
result += "\n]\n";
} else {
for (auto line : errLines) {
for (const auto& line : errLines) {
result += std::format("{}\n", line);
}
}
@@ -811,28 +818,28 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ
std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = "";
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto const& kb : g_pKeybindManager->m_lKeybinds) {
for (auto const& kb : g_pKeybindManager->m_vKeybinds) {
ret += "bind";
if (kb.locked)
if (kb->locked)
ret += "l";
if (kb.mouse)
if (kb->mouse)
ret += "m";
if (kb.release)
if (kb->release)
ret += "r";
if (kb.repeat)
if (kb->repeat)
ret += "e";
if (kb.nonConsuming)
if (kb->nonConsuming)
ret += "n";
if (kb.hasDescription)
if (kb->hasDescription)
ret += "d";
ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap,
kb.key, kb.keycode, kb.catchAll, kb.description, kb.handler, kb.arg);
ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb->modmask,
kb->submap, kb->key, kb->keycode, kb->catchAll, kb->description, kb->handler, kb->arg);
}
} else {
// json
ret += "[";
for (auto const& kb : g_pKeybindManager->m_lKeybinds) {
for (auto const& kb : g_pKeybindManager->m_vKeybinds) {
ret += std::format(
R"#(
{{
@@ -840,6 +847,7 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
"mouse": {},
"release": {},
"repeat": {},
"longPress": {},
"non_consuming": {},
"has_description": {},
"modmask": {},
@@ -851,9 +859,9 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
"dispatcher": "{}",
"arg": "{}"
}},)#",
kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false",
kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false",
escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg));
kb->locked ? "true" : "false", kb->mouse ? "true" : "false", kb->release ? "true" : "false", kb->repeat ? "true" : "false", kb->longPress ? "true" : "false",
kb->nonConsuming ? "true" : "false", kb->hasDescription ? "true" : "false", kb->modmask, escapeJSONStrings(kb->submap), escapeJSONStrings(kb->key), kb->keycode,
kb->catchAll ? "true" : "false", escapeJSONStrings(kb->description), escapeJSONStrings(kb->handler), escapeJSONStrings(kb->arg));
}
trimTrailingComma(ret);
ret += "]";
@@ -871,8 +879,9 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n"
"Date: {}\n"
"Tag: {}, commits: {}\n"
"built against aquamarine {}\n\n\n",
HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION);
"built against:\n aquamarine {}\n hyprlang {}\n hyprutils {}\n hyprcursor {}\n hyprgraphics {}\n\n\n",
HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION,
HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION);
#if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND))
result += "no flags were set\n";
@@ -901,9 +910,13 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
"tag": "{}",
"commits": "{}",
"buildAquamarine": "{}",
"buildHyprlang": "{}",
"buildHyprutils": "{}",
"buildHyprcursor": "{}",
"buildHyprgraphics": "{}",
"flags": [)#",
GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG,
GIT_COMMITS, AQUAMARINE_VERSION);
GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION);
#ifdef LEGACY_RENDERER
result += "\"legacyrenderer\",";
@@ -942,18 +955,51 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
result += "\n\n";
#if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga");
#elif defined(__arm__) || defined(__aarch64__)
const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible");
std::string GPUINFO;
const std::filesystem::path dev_tree = "/proc/device-tree";
try {
if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) {
std::for_each(std::filesystem::directory_iterator(dev_tree), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& entry) {
if (std::filesystem::is_directory(entry) && entry.path().filename().string().starts_with("soc")) {
std::for_each(std::filesystem::directory_iterator(entry.path()), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& sub_entry) {
if (std::filesystem::is_directory(sub_entry) && sub_entry.path().filename().string().starts_with("gpu")) {
std::filesystem::path file_path = sub_entry.path() / "compatible";
std::ifstream file(file_path);
if (file)
GPUINFO.append(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
}
});
}
});
}
} catch (...) { GPUINFO = "error"; }
#else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif
result += "GPU information: \n" + GPUINFO;
if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version"))
result += execAndGet("cat /proc/driver/nvidia/version | grep NVRM");
if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version")) {
std::ifstream file("/proc/driver/nvidia/version");
std::string line;
if (file.is_open()) {
while (std::getline(file, line)) {
if (!line.contains("NVRM"))
continue;
result += line;
result += "\n";
}
} else
result += "error";
}
result += "\n\n";
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
if (std::ifstream file("/etc/os-release"); file.is_open()) {
std::stringstream buffer;
buffer << file.rdbuf();
result += "os-release: " + buffer.str() + "\n\n";
} else
result += "os-release: error\n\n";
result += "plugins:\n";
if (g_pPluginSystem) {
@@ -1249,7 +1295,7 @@ std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
return "ok";
}
const CColor COLOR = configStringToInt(vars[1]);
const CHyprColor COLOR = configStringToInt(vars[1]).value_or(0);
for (size_t i = 2; i < vars.size(); ++i)
errorMessage += vars[i] + ' ';
@@ -1310,17 +1356,16 @@ std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request)
return std::format("custom type: {}\nset: {}", ((ICustomConfigValueData*)std::any_cast<void*>(VAL))->toString(), VAR->m_bSetByUser);
} else {
if (TYPE == typeid(Hyprlang::INT))
return std::format("{{\"option\": \"{}\", \"int\": {}, \"set\": {} }}", curitem, std::any_cast<Hyprlang::INT>(VAL), VAR->m_bSetByUser);
return std::format(R"({{"option": "{}", "int": {}, "set": {} }})", curitem, std::any_cast<Hyprlang::INT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::FLOAT))
return std::format("{{\"option\": \"{}\", \"float\": {:2f}, \"set\": {} }}", curitem, std::any_cast<Hyprlang::FLOAT>(VAL), VAR->m_bSetByUser);
return std::format(R"({{"option": "{}", "float": {:2f}, "set": {} }})", curitem, std::any_cast<Hyprlang::FLOAT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::VEC2))
return std::format("{{\"option\": \"{}\", \"vec2\": [{},{}], \"set\": {} }}", curitem, std::any_cast<Hyprlang::VEC2>(VAL).x, std::any_cast<Hyprlang::VEC2>(VAL).y,
return std::format(R"({{"option": "{}", "vec2": [{},{}], "set": {} }})", curitem, std::any_cast<Hyprlang::VEC2>(VAL).x, std::any_cast<Hyprlang::VEC2>(VAL).y,
VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::STRING))
return std::format("{{\"option\": \"{}\", \"str\": \"{}\", \"set\": {} }}", curitem, escapeJSONStrings(std::any_cast<Hyprlang::STRING>(VAL)), VAR->m_bSetByUser);
return std::format(R"({{"option": "{}", "str": "{}", "set": {} }})", curitem, escapeJSONStrings(std::any_cast<Hyprlang::STRING>(VAL)), VAR->m_bSetByUser);
else if (TYPE == typeid(void*))
return std::format("{{\"option\": \"{}\", \"custom\": \"{}\", \"set\": {} }}", curitem, ((ICustomConfigValueData*)std::any_cast<void*>(VAL))->toString(),
VAR->m_bSetByUser);
return std::format(R"({{"option": "{}", "custom": "{}", "set": {} }})", curitem, ((ICustomConfigValueData*)std::any_cast<void*>(VAL))->toString(), VAR->m_bSetByUser);
}
return "invalid type (internal error)";
@@ -1435,17 +1480,40 @@ std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
g_pPluginSystem->unloadPlugin(PLUGIN);
} else if (OPERATION == "list") {
const auto PLUGINS = g_pPluginSystem->getAllPlugins();
const auto PLUGINS = g_pPluginSystem->getAllPlugins();
std::string result = "";
if (PLUGINS.size() == 0)
return "no plugins loaded";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
std::string list = "";
for (auto const& p : PLUGINS) {
list += std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description);
if (PLUGINS.size() == 0)
return "[]";
for (auto const& p : PLUGINS) {
result += std::format(
R"#(
{{
"name": "{}",
"author": "{}",
"handle": "{:x}",
"version": "{}",
"description": "{}"
}},)#",
escapeJSONStrings(p->name), escapeJSONStrings(p->author), (uintptr_t)p->m_pHandle, escapeJSONStrings(p->version), escapeJSONStrings(p->description));
}
trimTrailingComma(result);
result += "]";
} else {
if (PLUGINS.size() == 0)
return "no plugins loaded";
for (auto const& p : PLUGINS) {
result +=
std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description);
}
}
return list;
return result;
} else {
return "unknown opt";
}
@@ -1469,9 +1537,8 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
icon = std::stoi(ICON);
} catch (std::exception& e) { return "invalid arg 1"; }
if (icon > ICON_NONE || icon < 0) {
if (icon > ICON_NONE || icon < 0)
icon = ICON_NONE;
}
const auto TIME = vars[2];
int time = 0;
@@ -1479,10 +1546,13 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
time = std::stoi(TIME);
} catch (std::exception& e) { return "invalid arg 2"; }
CColor color = configStringToInt(vars[3]);
const auto COLOR_RESULT = configStringToInt(vars[3]);
if (!COLOR_RESULT)
return "invalid arg 3";
CHyprColor color = *COLOR_RESULT;
size_t msgidx = 4;
float fontsize = 13.f;
size_t msgidx = 4;
float fontsize = 13.f;
if (vars[msgidx].length() > 9 && vars[msgidx].compare(0, 9, "fontsize:") == 0) {
const auto FONTSIZE = vars[msgidx].substr(9);
@@ -1702,7 +1772,7 @@ std::string CHyprCtl::getReply(std::string request) {
}
for (auto const& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || !g_pCompositor->isWorkspaceVisible(w->m_pWorkspace))
if (!w->m_bIsMapped || !w->m_pWorkspace || !w->m_pWorkspace->isVisible())
continue;
w->updateDynamicRules();
@@ -1740,13 +1810,13 @@ void runWritingDebugLogThread(const int conn) {
Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn);
//will be finished, when reading side close connection
std::thread([conn]() {
while (Debug::RollingLogFollow::Get().IsRunning()) {
if (Debug::RollingLogFollow::Get().isEmpty(conn)) {
while (Debug::SRollingLogFollow::get().isRunning()) {
if (Debug::SRollingLogFollow::get().isEmpty(conn)) {
std::this_thread::sleep_for(1000ms);
continue;
}
auto line = Debug::RollingLogFollow::Get().GetLog(conn);
auto line = Debug::SRollingLogFollow::get().getLog(conn);
if (!successWrite(conn, line))
// We cannot write, when connection is closed. So thread will successfully exit by itself
break;
@@ -1754,7 +1824,7 @@ void runWritingDebugLogThread(const int conn) {
std::this_thread::sleep_for(100ms);
}
close(conn);
Debug::RollingLogFollow::Get().StopFor(conn);
Debug::SRollingLogFollow::get().stopFor(conn);
}).detach();
}
@@ -1813,9 +1883,9 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
if (isFollowUpRollingLogRequest(request)) {
Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket.");
Debug::RollingLogFollow::Get().StartFor(ACCEPTEDCONNECTION);
Debug::SRollingLogFollow::get().startFor(ACCEPTEDCONNECTION);
runWritingDebugLogThread(ACCEPTEDCONNECTION);
Debug::log(LOG, Debug::RollingLogFollow::Get().DebugInfo());
Debug::log(LOG, Debug::SRollingLogFollow::get().debugInfo());
} else
close(ACCEPTEDCONNECTION);

View File

@@ -8,7 +8,12 @@ CHyprDebugOverlay::CHyprDebugOverlay() {
}
void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
m_dLastRenderTimes.push_back(durationUs / 1000.f);
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_dLastRenderTimes.emplace_back(durationUs / 1000.f);
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimes.pop_front();
@@ -18,7 +23,12 @@ void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs)
}
void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f);
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_dLastRenderTimesNoOverlay.emplace_back(durationUs / 1000.f);
if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimesNoOverlay.pop_front();
@@ -28,7 +38,12 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float du
}
void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
m_dLastFrametimes.push_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_dLastFrametimes.emplace_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f);
if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastFrametimes.pop_front();
@@ -189,14 +204,29 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
}
void CHyprDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs);
}
void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
}
void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) {
static auto PDEBUGOVERLAY = CConfigValue<Hyprlang::INT>("debug:overlay");
if (!*PDEBUGOVERLAY)
return;
m_mMonitorOverlays[pMonitor].frameData(pMonitor);
}

View File

@@ -3,9 +3,9 @@
#include "../defines.hpp"
#include "../helpers/Monitor.hpp"
#include "../render/Texture.hpp"
#include <deque>
#include <cairo/cairo.h>
#include <map>
#include <deque>
class CHyprRenderer;

View File

@@ -18,7 +18,7 @@ inline auto iconBackendFromLayout(PangoLayout* layout) {
CHyprNotificationOverlay::CHyprNotificationOverlay() {
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (m_dNotifications.size() == 0)
if (m_vNotifications.size() == 0)
return;
g_pHyprRenderer->damageBox(&m_bLastDamage);
@@ -34,11 +34,11 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() {
cairo_surface_destroy(m_pCairoSurface);
}
void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) {
const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) {
const auto PNOTIF = m_vNotifications.emplace_back(std::make_unique<SNotification>()).get();
PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text;
PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color;
PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color;
PNOTIF->started.reset();
PNOTIF->timeMs = timeMs;
PNOTIF->icon = icon;
@@ -51,12 +51,12 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC
void CHyprNotificationOverlay::dismissNotifications(const int amount) {
if (amount == -1)
m_dNotifications.clear();
m_vNotifications.clear();
else {
const int AMT = std::min(amount, static_cast<int>(m_dNotifications.size()));
const int AMT = std::min(amount, static_cast<int>(m_vNotifications.size()));
for (int i = 0; i < AMT; ++i) {
m_dNotifications.pop_front();
m_vNotifications.erase(m_vNotifications.begin());
}
}
}
@@ -87,7 +87,7 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
const auto iconBackendID = iconBackendFromLayout(layout);
const auto PBEZIER = g_pAnimationManager->getBezier("default");
for (auto const& notif : m_dNotifications) {
for (auto const& notif : m_vNotifications) {
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
@@ -182,7 +182,7 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
g_object_unref(layout);
// cleanup notifs
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
std::erase_if(m_vNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10};
}
@@ -205,7 +205,7 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
}
// Draw the notifications
if (m_dNotifications.size() == 0)
if (m_vNotifications.size() == 0)
return;
// Render to the monitor
@@ -246,5 +246,5 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
}
bool CHyprNotificationOverlay::hasAny() {
return !m_dNotifications.empty();
return !m_vNotifications.empty();
}

View File

@@ -6,11 +6,11 @@
#include "../render/Texture.hpp"
#include "../SharedDefs.hpp"
#include <deque>
#include <vector>
#include <cairo/cairo.h>
enum eIconBackend {
enum eIconBackend : uint8_t {
ICONS_BACKEND_NONE = 0,
ICONS_BACKEND_NF,
ICONS_BACKEND_FA
@@ -19,17 +19,17 @@ enum eIconBackend {
static const std::array<std::array<std::string, ICON_NONE + 1>, 3 /* backends */> ICONS_ARRAY = {
std::array<std::string, ICON_NONE + 1>{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""},
std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", "󰸞", ""}, std::array<std::string, ICON_NONE + 1>{"", "", "", "", "", ""}};
static const std::array<CColor, ICON_NONE + 1> ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
CColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
CColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
CColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
CColor{0, 0, 0, 1.0}};
static const std::array<CHyprColor, ICON_NONE + 1> ICONS_COLORS = {CHyprColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
CHyprColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
CHyprColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
CHyprColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
CHyprColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
CHyprColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
CHyprColor{0, 0, 0, 1.0}};
struct SNotification {
std::string text = "";
CColor color;
CHyprColor color;
CTimer started;
float timeMs = 0;
eIcons icon = ICON_NONE;
@@ -42,23 +42,23 @@ class CHyprNotificationOverlay {
~CHyprNotificationOverlay();
void draw(PHLMONITOR pMonitor);
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
void addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
void dismissNotifications(const int amount);
bool hasAny();
private:
CBox drawNotifications(PHLMONITOR pMonitor);
CBox m_bLastDamage;
CBox drawNotifications(PHLMONITOR pMonitor);
CBox m_bLastDamage;
std::deque<std::unique_ptr<SNotification>> m_dNotifications;
std::vector<std::unique_ptr<SNotification>> m_vNotifications;
cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr;
cairo_surface_t* m_pCairoSurface = nullptr;
cairo_t* m_pCairo = nullptr;
PHLMONITORREF m_pLastMonitor;
Vector2D m_vecLastSize = Vector2D(-1, -1);
PHLMONITORREF m_pLastMonitor;
Vector2D m_vecLastSize = Vector2D(-1, -1);
SP<CTexture> m_pTexture;
SP<CTexture> m_pTexture;
};
inline std::unique_ptr<CHyprNotificationOverlay> g_pHyprNotificationOverlay;

View File

@@ -18,7 +18,7 @@ void Debug::close() {
logOfs.close();
}
void Debug::log(LogLevel level, std::string str) {
void Debug::log(eLogLevel level, std::string str) {
if (level == TRACE && !trace)
return;
@@ -26,6 +26,7 @@ void Debug::log(LogLevel level, std::string str) {
return;
std::string coloredStr = str;
//NOLINTBEGIN
switch (level) {
case LOG:
str = "[LOG] " + str;
@@ -53,13 +54,14 @@ void Debug::log(LogLevel level, std::string str) {
break;
default: break;
}
//NOLINTEND
rollingLog += str + "\n";
if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
if (RollingLogFollow::Get().IsRunning())
RollingLogFollow::Get().AddLog(str);
if (SRollingLogFollow::get().isRunning())
SRollingLogFollow::get().addLog(str);
if (!disableLogs || !**disableLogs) {
// log to a file

View File

@@ -11,7 +11,7 @@
#define LOGMESSAGESIZE 1024
#define ROLLING_LOG_SIZE 4096
enum LogLevel {
enum eLogLevel : int8_t {
NONE = -1,
LOG = 0,
WARN,
@@ -21,6 +21,7 @@ enum LogLevel {
TRACE
};
// NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug {
inline std::string logFile;
inline std::ofstream logOfs;
@@ -38,10 +39,11 @@ namespace Debug {
void close();
//
void log(LogLevel level, std::string str);
void log(eLogLevel level, std::string str);
template <typename... Args>
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
//NOLINTNEXTLINE
void log(eLogLevel level, std::format_string<Args...> fmt, Args&&... args) {
std::lock_guard<std::mutex> guard(logMutex);
if (level == TRACE && !trace)

View File

@@ -2,8 +2,9 @@
#include <shared_mutex>
// NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug {
struct RollingLogFollow {
struct SRollingLogFollow {
std::unordered_map<int, std::string> socketToRollingLogFollowQueue;
std::shared_mutex m;
bool running = false;
@@ -15,12 +16,12 @@ namespace Debug {
return socketToRollingLogFollowQueue[socket].empty();
}
std::string DebugInfo() {
std::string debugInfo() {
std::shared_lock<std::shared_mutex> r(m);
return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size());
}
std::string GetLog(int socket) {
std::string getLog(int socket) {
std::unique_lock<std::shared_mutex> w(m);
const std::string ret = socketToRollingLogFollowQueue[socket];
@@ -29,7 +30,7 @@ namespace Debug {
return ret;
};
void AddLog(std::string log) {
void addLog(const std::string& log) {
std::unique_lock<std::shared_mutex> w(m);
running = true;
std::vector<int> to_erase;
@@ -37,26 +38,26 @@ namespace Debug {
socketToRollingLogFollowQueue[p.first] += log + "\n";
}
bool IsRunning() {
bool isRunning() {
std::shared_lock<std::shared_mutex> r(m);
return running;
}
void StopFor(int socket) {
void stopFor(int socket) {
std::unique_lock<std::shared_mutex> w(m);
socketToRollingLogFollowQueue.erase(socket);
if (socketToRollingLogFollowQueue.empty())
running = false;
}
void StartFor(int socket) {
void startFor(int socket) {
std::unique_lock<std::shared_mutex> w(m);
socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket);
running = true;
}
static RollingLogFollow& Get() {
static RollingLogFollow instance;
static SRollingLogFollow& get() {
static SRollingLogFollow instance;
static std::mutex gm;
std::lock_guard<std::mutex> lock(gm);
return instance;

37
src/desktop/LayerRule.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "LayerRule.hpp"
#include <unordered_set>
#include <algorithm>
#include "../debug/Log.hpp"
static const auto RULES = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"};
static const auto RULES_PREFIX = std::unordered_set<std::string>{"ignorealpha", "ignorezero", "xray", "animation", "order"};
CLayerRule::CLayerRule(const std::string& rule_, const std::string& ns_) : targetNamespace(ns_), rule(rule_) {
const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule_](const auto& prefix) { return rule_.starts_with(prefix); });
if (!VALID)
return;
if (rule == "noanim")
ruleType = RULE_NOANIM;
else if (rule == "blur")
ruleType = RULE_BLUR;
else if (rule == "blurpopups")
ruleType = RULE_BLURPOPUPS;
else if (rule == "dimaround")
ruleType = RULE_DIMAROUND;
else if (rule.starts_with("ignorealpha"))
ruleType = RULE_IGNOREALPHA;
else if (rule.starts_with("ignorezero"))
ruleType = RULE_IGNOREZERO;
else if (rule.starts_with("xray"))
ruleType = RULE_XRAY;
else if (rule.starts_with("animation"))
ruleType = RULE_ANIMATION;
else if (rule.starts_with("order"))
ruleType = RULE_ORDER;
else {
Debug::log(ERR, "CLayerRule: didn't match a rule that was found valid?!");
ruleType = RULE_INVALID;
}
}

28
src/desktop/LayerRule.hpp Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <cstdint>
class CLayerRule {
public:
CLayerRule(const std::string& rule, const std::string& targetNS);
enum eRuleType : uint8_t {
RULE_INVALID = 0,
RULE_NOANIM,
RULE_BLUR,
RULE_BLURPOPUPS,
RULE_DIMAROUND,
RULE_IGNOREALPHA,
RULE_IGNOREZERO,
RULE_XRAY,
RULE_ANIMATION,
RULE_ORDER,
RULE_ZUMBA,
};
eRuleType ruleType = RULE_INVALID;
const std::string targetNamespace;
const std::string rule;
};

View File

@@ -8,7 +8,7 @@
PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource));
auto pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor);
auto pMonitor = resource->monitor.empty() ? g_pCompositor->m_pLastMonitor.lock() : g_pCompositor->getMonitorFromName(resource->monitor);
pLS->surface->assign(resource->surface.lock(), pLS);
@@ -378,38 +378,57 @@ void CLayerSurface::applyRules() {
animationStyle.reset();
for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) {
if (rule.rule == "noanim")
noAnimations = true;
else if (rule.rule == "blur")
forceBlur = true;
else if (rule.rule == "blurpopups")
forceBlurPopups = true;
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)
alphaValue = rule.rule.substr(FIRST_SPACE_POS + 1);
switch (rule->ruleType) {
case CLayerRule::RULE_NOANIM: {
noAnimations = true;
break;
}
case CLayerRule::RULE_BLUR: {
forceBlur = true;
break;
}
case CLayerRule::RULE_BLURPOPUPS: {
forceBlurPopups = true;
break;
}
case CLayerRule::RULE_IGNOREALPHA:
case CLayerRule::RULE_IGNOREZERO: {
const auto FIRST_SPACE_POS = rule->rule.find_first_of(' ');
std::string alphaValue = "";
if (FIRST_SPACE_POS != std::string::npos)
alphaValue = rule->rule.substr(FIRST_SPACE_POS + 1);
try {
ignoreAlpha = true;
if (!alphaValue.empty())
ignoreAlphaValue = std::stof(alphaValue);
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
} else if (rule.rule == "dimaround") {
dimAround = true;
} else if (rule.rule.starts_with("xray")) {
CVarList vars{rule.rule, 0, ' '};
try {
xray = configStringToInt(vars[1]);
} catch (...) {}
} else if (rule.rule.starts_with("animation")) {
CVarList vars{rule.rule, 2, 's'};
animationStyle = vars[1];
} else if (rule.rule.starts_with("order")) {
CVarList vars{rule.rule, 2, 's'};
try {
order = std::stoi(vars[1]);
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
try {
ignoreAlpha = true;
if (!alphaValue.empty())
ignoreAlphaValue = std::stof(alphaValue);
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
break;
}
case CLayerRule::RULE_DIMAROUND: {
dimAround = true;
break;
}
case CLayerRule::RULE_XRAY: {
CVarList vars{rule->rule, 0, ' '};
try {
xray = configStringToInt(vars[1]).value_or(false);
} catch (...) {}
break;
}
case CLayerRule::RULE_ANIMATION: {
CVarList vars{rule->rule, 2, 's'};
animationStyle = vars[1];
break;
}
case CLayerRule::RULE_ORDER: {
CVarList vars{rule->rule, 2, 's'};
try {
order = std::stoi(vars[1]);
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
break;
}
default: break;
}
}
}

View File

@@ -4,11 +4,7 @@
#include "../defines.hpp"
#include "WLSurface.hpp"
#include "../helpers/AnimatedVariable.hpp"
struct SLayerRule {
std::string targetNamespace = "";
std::string rule = "";
};
#include "LayerRule.hpp"
class CLayerShellResource;

View File

@@ -16,13 +16,10 @@ CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) {
initAllSignals();
}
CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner), m_pResource(popup) {
CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) {
m_pWLSurface = CWLSurface::create();
m_pWLSurface->assign(popup->surface->surface.lock(), this);
m_pLayerOwner = pOwner->m_pLayerOwner;
m_pWindowOwner = pOwner->m_pWindowOwner;
m_vLastSize = popup->surface->current.geometry.size();
reposition();

View File

@@ -41,6 +41,7 @@ class CPopup {
//
SP<CWLSurface> m_pWLSurface;
bool m_bMapped = false;
private:
// T1 owners, each popup has to have one of these
@@ -57,8 +58,7 @@ class CPopup {
bool m_bRequestedReposition = false;
bool m_bInert = false;
bool m_bMapped = false;
bool m_bInert = false;
//
std::vector<SP<CPopup>> m_vChildren;

View File

@@ -1,3 +1,5 @@
#include <re2/re2.h>
#include <any>
#include <bit>
#include <string_view>
@@ -413,12 +415,12 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
setAnimationsToMove();
g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID);
g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID);
OLDWORKSPACE->updateWindows();
OLDWORKSPACE->updateWindowData();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->monitorID());
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
pWorkspace->updateWindows();
pWorkspace->updateWindowData();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -437,13 +439,13 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
// update xwayland coords
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value());
if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE->m_iID) == 0 && *PCLOSEONLASTSPECIAL) {
if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) {
if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR)
PMONITOR->setSpecialWorkspace(nullptr);
}
}
PHLWINDOW CWindow::X11TransientFor() {
PHLWINDOW CWindow::x11TransientFor() {
if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent)
return nullptr;
@@ -516,7 +518,7 @@ void CWindow::onUnmap() {
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; });
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) {
if (*PCLOSEONLASTSPECIAL && m_pWorkspace && m_pWorkspace->getWindows() == 0 && onSpecialWorkspace()) {
const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace)
PMONITOR->setSpecialWorkspace(nullptr);
@@ -527,8 +529,10 @@ void CWindow::onUnmap() {
if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this)
PMONITOR->solitaryClient.reset();
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
if (m_pWorkspace) {
m_pWorkspace->updateWindows();
m_pWorkspace->updateWindowData();
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -612,154 +616,179 @@ bool CWindow::isHidden() {
return m_bHidden;
}
void CWindow::applyDynamicRule(const SWindowRule& r) {
const eOverridePriority priority = r.szValue == "execRule" ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
const CVarList VARS(r.szRule, 0, ' ');
if (r.szRule.starts_with("tag")) {
CVarList vars{r.szRule, 0, 's', true};
void CWindow::applyDynamicRule(const SP<CWindowRule>& r) {
const eOverridePriority priority = r->execRule ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
if (vars.size() == 2 && vars[0] == "tag")
m_tags.applyTag(vars[1], true);
else
Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
} else if (r.szRule.starts_with("opacity")) {
try {
CVarList vars(r.szRule, 0, ' ');
switch (r->ruleType) {
case CWindowRule::RULE_TAG: {
CVarList vars{r->szRule, 0, 's', true};
int opacityIDX = 0;
for (auto const& r : vars) {
if (r == "opacity")
continue;
if (r == "override") {
if (opacityIDX == 1)
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
else if (opacityIDX == 2)
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority);
else if (opacityIDX == 3)
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
} else {
if (opacityIDX == 0) {
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 1) {
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 2) {
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else {
throw std::runtime_error("more than 3 alpha values");
}
opacityIDX++;
}
}
if (opacityIDX == 1) {
m_sWindowData.alphaInactive = m_sWindowData.alpha;
m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("animation")) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
} else if (r.szRule.starts_with("bordercolor")) {
try {
// Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {};
bool active = true;
CVarList colorsAndAngles = CVarList(trim(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
// Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))), priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))), priority);
return;
}
for (auto const& token : colorsAndAngles) {
// The first angle, or an explicit "0deg", splits the two gradients
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false;
} else if (token.contains("deg"))
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
else if (active)
activeBorderGradient.m_vColors.push_back(configStringToInt(token));
else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
}
// Includes sanity checks for the number of colors in each gradient
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
else if (inactiveBorderGradient.m_vColors.empty())
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else {
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[0]); search != g_pConfigManager->mbWindowProperties.end()) {
if (VARS[1].empty()) {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority);
} else {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]), priority);
} catch (...) {}
if (vars.size() == 2 && vars[0] == "tag")
m_tags.applyTag(vars[1], true);
else
Debug::log(ERR, "Tag rule invalid: {}", r->szRule);
break;
}
} else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[1]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
case CWindowRule::RULE_OPACITY: {
try {
CVarList vars(r->szRule, 0, ' ');
if (IDLERULE == "none")
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
else if (IDLERULE == "always")
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
else if (IDLERULE == "focus")
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
else if (IDLERULE == "fullscreen")
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
} else if (r.szRule.starts_with("maxsize")) {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r.szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for maxsize");
return;
int opacityIDX = 0;
for (auto const& r : vars) {
if (r == "opacity")
continue;
if (r == "override") {
if (opacityIDX == 1)
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
else if (opacityIDX == 2)
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority);
else if (opacityIDX == 3)
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
} else {
if (opacityIDX == 0) {
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 1) {
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 2) {
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else {
throw std::runtime_error("more than 3 alpha values");
}
opacityIDX++;
}
}
if (opacityIDX == 1) {
m_sWindowData.alphaInactive = m_sWindowData.alpha;
m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_ANIMATION: {
auto STYLE = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
break;
}
case CWindowRule::RULE_BORDERCOLOR: {
try {
// Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {};
bool active = true;
CVarList colorsAndAngles = CVarList(trim(r->szRule.substr(r->szRule.find_first_of(' ') + 1)), 0, 's', true);
// Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority);
return;
}
for (auto const& token : colorsAndAngles) {
// The first angle, or an explicit "0deg", splits the two gradients
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
active = false;
} else if (token.contains("deg"))
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
else if (active)
activeBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
else
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0));
}
activeBorderGradient.updateColorsOk();
// Includes sanity checks for the number of colors in each gradient
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r->szRule);
else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r->szRule);
else if (inactiveBorderGradient.m_vColors.empty())
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else {
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_IDLEINHIBIT: {
auto IDLERULE = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
if (IDLERULE == "none")
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
else if (IDLERULE == "always")
m_eIdleInhibitMode = IDLEINHIBIT_ALWAYS;
else if (IDLERULE == "focus")
m_eIdleInhibitMode = IDLEINHIBIT_FOCUS;
else if (IDLERULE == "fullscreen")
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
break;
}
case CWindowRule::RULE_MAXSIZE: {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r->szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for maxsize");
return;
}
m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(std::nullopt, m_sWindowData.maxSize.value());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_MINSIZE: {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r->szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for minsize");
return;
}
m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(m_sWindowData.minSize.value(), std::nullopt);
if (m_sGroupData.pNextWindow.expired())
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r->szRule, e.what()); }
break;
}
case CWindowRule::RULE_RENDERUNFOCUSED: {
m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority);
g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock());
break;
}
case CWindowRule::RULE_PROP: {
const CVarList VARS(r->szRule, 0, ' ');
if (auto search = g_pConfigManager->miWindowProperties.find(VARS[1]); search != g_pConfigManager->miWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = g_pConfigManager->mfWindowProperties.find(VARS[1]); search != g_pConfigManager->mfWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stof(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[1]); search != g_pConfigManager->mbWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(VARS[2].empty() ? true : (bool)std::stoi(VARS[2]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); }
}
m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(std::nullopt, m_sWindowData.maxSize.value());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("minsize")) {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r.szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for minsize");
return;
}
m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
clampWindowSize(m_sWindowData.minSize.value(), std::nullopt);
if (m_sGroupData.pNextWindow.expired())
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "renderunfocused") {
m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority);
g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock());
break;
}
default: break;
}
}
@@ -784,7 +813,7 @@ void CWindow::updateDynamicRules() {
m_tags.removeDynamicTags();
m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock());
for (auto const& r : m_vMatchedRules) {
for (const auto& r : m_vMatchedRules) {
applyDynamicRule(r);
}
@@ -855,8 +884,10 @@ void CWindow::createGroup() {
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock()));
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
if (m_pWorkspace) {
m_pWorkspace->updateWindows();
m_pWorkspace->updateWindowData();
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -873,8 +904,10 @@ void CWindow::destroyGroup() {
m_sGroupData.pNextWindow.reset();
m_sGroupData.head = false;
updateWindowDecos();
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
if (m_pWorkspace) {
m_pWorkspace->updateWindows();
m_pWorkspace->updateWindowData();
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -909,8 +942,10 @@ void CWindow::destroyGroup() {
}
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
if (m_pWorkspace) {
m_pWorkspace->updateWindows();
m_pWorkspace->updateWindowData();
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -1168,6 +1203,16 @@ int CWindow::getRealBorderSize() {
return m_sWindowData.borderSize.valueOr(*PBORDERSIZE);
}
float CWindow::getScrollMouse() {
static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor");
return m_sWindowData.scrollMouse.valueOr(*PINPUTSCROLLFACTOR);
}
float CWindow::getScrollTouchpad() {
static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor");
return m_sWindowData.scrollTouchpad.valueOr(*PTOUCHPADSCROLLFACTOR);
}
bool CWindow::canBeTorn() {
static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING;
@@ -1507,7 +1552,7 @@ void CWindow::onX11Configure(CBox box) {
updateWindowDecos();
if (!g_pCompositor->isWorkspaceVisible(m_pWorkspace))
if (!m_pWorkspace || !m_pWorkspace->isVisible())
return; // further things are only for visible windows
m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace;
@@ -1519,15 +1564,15 @@ void CWindow::onX11Configure(CBox box) {
g_pHyprRenderer->damageWindow(m_pSelf.lock());
}
void CWindow::warpCursor() {
void CWindow::warpCursor(bool force) {
static auto PERSISTENTWARPS = CConfigValue<Hyprlang::INT>("cursor:persistent_warps");
const auto coords = m_vRelativeCursorCoordsOnLastWarp;
m_vRelativeCursorCoordsOnLastWarp.x = -1; // reset m_vRelativeCursorCoordsOnLastWarp
if (*PERSISTENTWARPS && coords.x > 0 && coords.y > 0 && coords < m_vSize) // don't warp cursor outside the window
g_pCompositor->warpCursorTo(m_vPosition + coords);
g_pCompositor->warpCursorTo(m_vPosition + coords, force);
else
g_pCompositor->warpCursorTo(middle());
g_pCompositor->warpCursorTo(middle(), force);
}
PHLWINDOW CWindow::getSwallower() {
@@ -1558,13 +1603,13 @@ PHLWINDOW CWindow::getSwallower() {
}
if (!(*PSWALLOWREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return !std::regex_match(other->m_szClass, std::regex(*PSWALLOWREGEX)); });
std::erase_if(candidates, [&](const auto& other) { return !RE2::FullMatch(other->m_szClass, *PSWALLOWREGEX); });
if (candidates.size() <= 0)
return nullptr;
if (!(*PSWALLOWEXREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return std::regex_match(other->m_szTitle, std::regex(*PSWALLOWEXREGEX)); });
std::erase_if(candidates, [&](const auto& other) { return RE2::FullMatch(other->m_szTitle, *PSWALLOWEXREGEX); });
if (candidates.size() <= 0)
return nullptr;
@@ -1592,6 +1637,9 @@ void CWindow::unsetWindowData(eOverridePriority priority) {
for (auto const& element : g_pConfigManager->miWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
for (auto const& element : g_pConfigManager->mfWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
}
bool CWindow::isX11OverrideRedirect() {
@@ -1601,3 +1649,29 @@ bool CWindow::isX11OverrideRedirect() {
bool CWindow::isModal() {
return (m_pXWaylandSurface && m_pXWaylandSurface->modal);
}
Vector2D CWindow::requestedMinSize() {
if ((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel))
return Vector2D(1, 1);
Vector2D minSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->min_width, m_pXWaylandSurface->sizeHints->min_height) : m_pXDGSurface->toplevel->layoutMinSize();
minSize = minSize.clamp({1, 1});
return minSize;
}
Vector2D CWindow::requestedMaxSize() {
constexpr int NO_MAX_SIZE_LIMIT = 99999;
if (((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel) || m_sWindowData.noMaxSize.valueOrDefault()))
return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT);
Vector2D maxSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->max_width, m_pXWaylandSurface->sizeHints->max_height) : m_pXDGSurface->toplevel->layoutMaxSize();
if (maxSize.x < 5)
maxSize.x = NO_MAX_SIZE_LIMIT;
if (maxSize.y < 5)
maxSize.y = NO_MAX_SIZE_LIMIT;
return maxSize;
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include <deque>
#include <vector>
#include <string>
#include "../config/ConfigDataValues.hpp"
@@ -17,18 +17,19 @@
#include "Subsurface.hpp"
#include "WLSurface.hpp"
#include "Workspace.hpp"
#include "WindowRule.hpp"
class CXDGSurfaceResource;
class CXWaylandSurface;
enum eIdleInhibitMode {
enum eIdleInhibitMode : uint8_t {
IDLEINHIBIT_NONE = 0,
IDLEINHIBIT_ALWAYS,
IDLEINHIBIT_FULLSCREEN,
IDLEINHIBIT_FOCUS
};
enum eGroupRules {
enum eGroupRules : uint8_t {
// 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
@@ -40,7 +41,7 @@ enum eGroupRules {
GROUP_OVERRIDE = 1 << 6, // Override other rules
};
enum eGetWindowProperties {
enum eGetWindowProperties : uint8_t {
WINDOW_ONLY = 0,
RESERVED_EXTENTS = 1 << 0,
INPUT_EXTENTS = 1 << 1,
@@ -50,7 +51,7 @@ enum eGetWindowProperties {
USE_PROP_TILED = 1 << 5,
};
enum eSuppressEvents {
enum eSuppressEvents : uint8_t {
SUPPRESS_NONE = 0,
SUPPRESS_FULLSCREEN = 1 << 0,
SUPPRESS_MAXIMIZE = 1 << 1,
@@ -64,7 +65,7 @@ struct SAlphaValue {
float m_fAlpha;
bool m_bOverride;
float applyAlpha(float alpha) {
float applyAlpha(float alpha) const {
if (m_bOverride)
return m_fAlpha;
else
@@ -72,8 +73,8 @@ struct SAlphaValue {
};
};
enum eOverridePriority {
PRIORITY_LAYOUT,
enum eOverridePriority : uint8_t {
PRIORITY_LAYOUT = 0,
PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP,
@@ -85,9 +86,7 @@ class CWindowOverridableVar {
CWindowOverridableVar(T const& value, eOverridePriority priority) {
values[priority] = value;
}
CWindowOverridableVar(T const& value) {
defaultValue = value;
}
CWindowOverridableVar(T const& value) : defaultValue{value} {}
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default;
@@ -186,6 +185,9 @@ struct SWindowData {
CWindowOverridableVar<int> rounding;
CWindowOverridableVar<int> borderSize;
CWindowOverridableVar<float> scrollMouse;
CWindowOverridableVar<float> scrollTouchpad;
CWindowOverridableVar<std::string> animationStyle;
CWindowOverridableVar<Vector2D> maxSize;
CWindowOverridableVar<Vector2D> minSize;
@@ -194,32 +196,12 @@ struct SWindowData {
CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
};
struct SWindowRule {
std::string szRule;
std::string szValue;
bool v2 = false;
std::string szTitle;
std::string szClass;
std::string szInitialTitle;
std::string szInitialClass;
std::string szTag;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
int bFullscreen = -1;
int bPinned = -1;
int bFocus = -1;
std::string szFullscreenState = ""; // empty means any
std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any
};
struct SInitialWorkspaceToken {
PHLWINDOWREF primaryOwner;
std::string workspace;
};
struct sFullscreenState {
struct SFullscreenState {
eFullscreenMode internal = FSMODE_NONE;
eFullscreenMode client = FSMODE_NONE;
};
@@ -278,7 +260,7 @@ class CWindow {
bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bWasMaximized = false;
sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
SFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
std::string m_szTitle = "";
std::string m_szClass = "";
std::string m_szInitialTitle = "";
@@ -332,6 +314,9 @@ class CWindow {
// For pinned (sticky) windows
bool m_bPinned = false;
// For preserving pinned state when fullscreening a pinned window
bool m_bPinFullscreened = false;
// urgency hint
bool m_bIsUrgent = false;
@@ -340,8 +325,8 @@ class CWindow {
// Window decorations
// TODO: make this a SP.
std::deque<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations;
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
std::vector<std::unique_ptr<IHyprWindowDecoration>> m_dWindowDecorations;
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
// Special render data, rules, etc
SWindowData m_sWindowData;
@@ -353,7 +338,7 @@ class CWindow {
CAnimatedVariable<float> m_fActiveInactiveAlpha;
// animated shadow color
CAnimatedVariable<CColor> m_cRealShadowColor;
CAnimatedVariable<CHyprColor> m_cRealShadowColor;
// animated tint
CAnimatedVariable<float> m_fDimPercent;
@@ -391,24 +376,21 @@ class CWindow {
bool m_bTearingHint = false;
// stores the currently matched window rules
std::vector<SWindowRule> m_vMatchedRules;
std::vector<SP<CWindowRule>> m_vMatchedRules;
// window tags
CTagKeeper m_tags;
// For the list lookup
bool operator==(const CWindow& rhs) {
bool operator==(const CWindow& rhs) const {
return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
m_bFadingOut == rhs.m_bFadingOut;
}
// methods
CBox getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props);
inline CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
CBox getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props);
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos();
@@ -421,12 +403,12 @@ class CWindow {
void updateToplevel();
void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW X11TransientFor();
PHLWINDOW x11TransientFor();
void onUnmap();
void onMap();
void setHidden(bool hidden);
bool isHidden();
void applyDynamicRule(const SWindowRule& r);
void applyDynamicRule(const SP<CWindowRule>& r);
void updateDynamicRules();
SBoxExtents getFullWindowReservedArea();
Vector2D middle();
@@ -441,19 +423,17 @@ class CWindow {
void activate(bool force = false);
int surfacesCount();
void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize();
float getScrollMouse();
float getScrollTouchpad();
void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(void* ptr);
bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos);
int popupsCount();
void applyGroupRules();
void createGroup();
void destroyGroup();
@@ -476,11 +456,17 @@ class CWindow {
void onResourceChangeX11();
std::string fetchTitle();
std::string fetchClass();
void warpCursor();
void warpCursor(bool force = false);
PHLWINDOW getSwallower();
void unsetWindowData(eOverridePriority priority);
bool isX11OverrideRedirect();
bool isModal();
Vector2D requestedMinSize();
Vector2D requestedMaxSize();
CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
// listeners
void onAck(uint32_t serial);

View File

@@ -0,0 +1,90 @@
#include "WindowRule.hpp"
#include <unordered_set>
#include <algorithm>
#include "../config/ConfigManager.hpp"
static const auto RULES = std::unordered_set<std::string>{
"float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused",
};
static const auto RULES_PREFIX = std::unordered_set<std::string>{
"animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity",
"plugin:", "prop", "pseudo", "rounding", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray",
};
CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) {
const auto VALS = CVarList(rule, 2, ' ');
const bool VALID = RULES.contains(rule) || std::any_of(RULES_PREFIX.begin(), RULES_PREFIX.end(), [&rule](auto prefix) { return rule.starts_with(prefix); }) ||
(g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) ||
(g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end()) ||
(g_pConfigManager->mfWindowProperties.find(VALS[0]) != g_pConfigManager->mfWindowProperties.end());
if (!VALID)
return;
if (rule == "float")
ruleType = RULE_FLOAT;
else if (rule == "fullscreen")
ruleType = RULE_FULLSCREEN;
else if (rule == "maximize")
ruleType = RULE_MAXIMIZE;
else if (rule == "noinitialfocus")
ruleType = RULE_NOINITIALFOCUS;
else if (rule == "pin")
ruleType = RULE_PIN;
else if (rule == "stayfocused")
ruleType = RULE_STAYFOCUSED;
else if (rule == "tile")
ruleType = RULE_TILE;
else if (rule == "renderunfocused")
ruleType = RULE_RENDERUNFOCUSED;
else if (rule.starts_with("animation"))
ruleType = RULE_ANIMATION;
else if (rule.starts_with("bordercolor"))
ruleType = RULE_BORDERCOLOR;
else if (rule.starts_with("center"))
ruleType = RULE_CENTER;
else if (rule.starts_with("fullscreenstate"))
ruleType = RULE_FULLSCREENSTATE;
else if (rule.starts_with("group"))
ruleType = RULE_GROUP;
else if (rule.starts_with("idleinhibit"))
ruleType = RULE_IDLEINHIBIT;
else if (rule.starts_with("maxsize"))
ruleType = RULE_MAXSIZE;
else if (rule.starts_with("minsize"))
ruleType = RULE_MINSIZE;
else if (rule.starts_with("monitor"))
ruleType = RULE_MONITOR;
else if (rule.starts_with("move"))
ruleType = RULE_MOVE;
else if (rule.starts_with("opacity"))
ruleType = RULE_OPACITY;
else if (rule.starts_with("plugin:"))
ruleType = RULE_PLUGIN;
else if (rule.starts_with("pseudo"))
ruleType = RULE_PSEUDO;
else if (rule.starts_with("size"))
ruleType = RULE_SIZE;
else if (rule.starts_with("suppressevent"))
ruleType = RULE_SUPPRESSEVENT;
else if (rule.starts_with("tag"))
ruleType = RULE_TAG;
else if (rule.starts_with("workspace"))
ruleType = RULE_WORKSPACE;
else if (rule.starts_with("prop"))
ruleType = RULE_PROP;
else {
// check if this is a prop.
const CVarList VARS(rule, 0, 's', true);
if (g_pConfigManager->miWindowProperties.find(VARS[0]) != g_pConfigManager->miWindowProperties.end() ||
g_pConfigManager->mbWindowProperties.find(VARS[0]) != g_pConfigManager->mbWindowProperties.end() ||
g_pConfigManager->mfWindowProperties.find(VARS[0]) != g_pConfigManager->mfWindowProperties.end()) {
*const_cast<std::string*>(&szRule) = "prop " + rule;
ruleType = RULE_PROP;
Debug::log(LOG, "CWindowRule: direct prop rule found, rewritten {} -> {}", rule, szRule);
} else {
Debug::log(ERR, "CWindowRule: didn't match a rule that was found valid?!");
ruleType = RULE_INVALID;
}
}
}

View File

@@ -0,0 +1,60 @@
#pragma once
#include <string>
#include <cstdint>
class CWindowRule {
public:
CWindowRule(const std::string& rule, const std::string& value, bool isV2 = false, bool isExecRule = false);
enum eRuleType : uint8_t {
RULE_INVALID = 0,
RULE_FLOAT,
RULE_FULLSCREEN,
RULE_MAXIMIZE,
RULE_NOINITIALFOCUS,
RULE_PIN,
RULE_STAYFOCUSED,
RULE_TILE,
RULE_RENDERUNFOCUSED,
RULE_ANIMATION,
RULE_BORDERCOLOR,
RULE_CENTER,
RULE_FULLSCREENSTATE,
RULE_GROUP,
RULE_IDLEINHIBIT,
RULE_MAXSIZE,
RULE_MINSIZE,
RULE_MONITOR,
RULE_MOVE,
RULE_OPACITY,
RULE_PLUGIN,
RULE_PSEUDO,
RULE_SIZE,
RULE_SUPPRESSEVENT,
RULE_TAG,
RULE_WORKSPACE,
RULE_PROP,
};
eRuleType ruleType = RULE_INVALID;
const std::string szValue;
const std::string szRule;
const bool v2 = false;
const bool execRule = false;
std::string szTitle;
std::string szClass;
std::string szInitialTitle;
std::string szInitialClass;
std::string szTag;
int bX11 = -1; // -1 means "ANY"
int bFloating = -1;
int bFullscreen = -1;
int bPinned = -1;
int bFocus = -1;
std::string szFullscreenState = ""; // empty means any
std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any
};

View File

@@ -11,12 +11,9 @@ PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string
return workspace;
}
CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) {
m_pMonitor = monitor;
m_iID = id;
m_szName = name;
m_bIsSpecialWorkspace = special;
m_bWasCreatedEmpty = isEmpty;
CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) :
m_iID(id), m_szName(name), m_pMonitor(monitor), m_bIsSpecialWorkspace(special), m_bWasCreatedEmpty(isEmpty) {
;
}
void CWorkspace::init(PHLWORKSPACE self) {
@@ -106,7 +103,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
const auto PMONITOR = m_pMonitor.lock();
float movePerc = 100.f;
if (ANIMSTYLE.find("%") != std::string::npos) {
if (ANIMSTYLE.find('%') != std::string::npos) {
try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1);
movePerc = std::stoi(percstr.substr(0, percstr.length() - 1));
@@ -278,9 +275,9 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
// f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states
// -1: no fullscreen, 0: fullscreen, 1: maximized, 2: fullscreen without sending fs state to window
const auto NEXTSPACE = selector.find_first_of(' ', i);
std::string prop = selector.substr(i, NEXTSPACE == std::string::npos ? std::string::npos : NEXTSPACE - i);
i = std::min(NEXTSPACE, std::string::npos - 1);
const auto CLOSING_BRACKET = selector.find_first_of(']', i);
std::string prop = selector.substr(i, CLOSING_BRACKET == std::string::npos ? std::string::npos : CLOSING_BRACKET + 1 - i);
i = std::min(CLOSING_BRACKET, std::string::npos - 1);
if (cur == 'r') {
WORKSPACEID from = 0, to = 0;
@@ -296,7 +293,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false;
}
const auto DASHPOS = prop.find("-");
const auto DASHPOS = prop.find('-');
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) {
@@ -332,7 +329,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto SHOULDBESPECIAL = configStringToInt(prop);
if ((bool)SHOULDBESPECIAL != m_bIsSpecialWorkspace)
if (SHOULDBESPECIAL && (bool)*SHOULDBESPECIAL != m_bIsSpecialWorkspace)
return false;
continue;
}
@@ -367,7 +364,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto WANTSNAMED = configStringToInt(prop);
if (WANTSNAMED != (m_iID <= -1337))
if (WANTSNAMED && *WANTSNAMED != (m_iID <= -1337))
return false;
continue;
}
@@ -422,18 +419,18 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
int count;
if (wantsCountGroup)
count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else
count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (count != from)
return false;
continue;
}
const auto DASHPOS = prop.find("-");
const auto DASHPOS = prop.find('-');
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) {
@@ -456,11 +453,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
WORKSPACEID count;
if (wantsCountGroup)
count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
else
count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
if (std::clamp(count, from, to) != count)
return false;
@@ -525,3 +522,138 @@ bool CWorkspace::inert() {
MONITORID CWorkspace::monitorID() {
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID;
}
PHLWINDOW CWorkspace::getFullscreenWindow() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->isFullscreen())
return w;
}
return nullptr;
}
bool CWorkspace::isVisible() {
return m_bVisible;
}
bool CWorkspace::isVisibleNotCovered() {
const auto PMONITOR = m_pMonitor.lock();
if (PMONITOR->activeSpecialWorkspace)
return PMONITOR->activeSpecialWorkspace->m_iID == m_iID;
return PMONITOR->activeWorkspace->m_iID == m_iID;
}
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
}
return no;
}
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyVisible) {
int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped)
continue;
if (!w->m_sGroupData.head)
continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value())
continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue;
no++;
}
return no;
}
PHLWINDOW CWorkspace::getFirstWindow() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && !w->isHidden())
return w;
}
return nullptr;
}
PHLWINDOW CWorkspace::getTopLeftWindow() {
const auto PMONITOR = m_pMonitor.lock();
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue;
const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
if (WINDOWIDEALBB.x <= PMONITOR->vecPosition.x + 1 && WINDOWIDEALBB.y <= PMONITOR->vecPosition.y + 1)
return w;
}
return nullptr;
}
bool CWorkspace::hasUrgentWindow() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && w->m_bIsUrgent)
return true;
}
return false;
}
void CWorkspace::updateWindowDecos() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf)
continue;
w->updateWindowDecos();
}
}
void CWorkspace::updateWindowData() {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock());
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf)
continue;
w->updateWindowData(WORKSPACERULE);
}
}
void CWorkspace::forceReportSizesToWindows() {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden())
continue;
g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true);
}
}
void CWorkspace::rename(const std::string& name) {
if (g_pCompositor->isWorkspaceSpecial(m_iID))
return;
Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name);
m_szName = name;
g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName});
}
void CWorkspace::updateWindows() {
m_bHasFullscreenWindow = std::ranges::any_of(g_pCompositor->m_vWindows, [this](const auto& w) { return w->m_bIsMapped && w->m_pWorkspace == m_pSelf && w->isFullscreen(); });
for (auto const& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_pWorkspace != m_pSelf)
continue;
w->updateDynamicRules();
}
}

View File

@@ -63,23 +63,29 @@ class CWorkspace {
// Inert: destroyed and invalid. If this is true, release the ptr you have.
bool inert();
void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on);
void moveToMonitor(const MONITORID&);
MONITORID monitorID();
PHLWINDOW getLastFocusedWindow();
void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);
std::string getConfigName();
bool matchesStaticSelector(const std::string& selector);
void markInert();
SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const;
void updateWindowDecos();
void updateWindowData();
int getWindows(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroups(std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
bool hasUrgentWindow();
PHLWINDOW getFirstWindow();
PHLWINDOW getTopLeftWindow();
PHLWINDOW getFullscreenWindow();
bool isVisible();
bool isVisibleNotCovered();
void rename(const std::string& name = "");
void forceReportSizesToWindows();
void updateWindows();
private:
void init(PHLWORKSPACE self);

View File

@@ -4,14 +4,14 @@
#include <string>
#include "../helpers/signal/Signal.hpp"
enum eHIDCapabilityType : uint32_t {
enum eHIDCapabilityType : uint8_t {
HID_INPUT_CAPABILITY_KEYBOARD = (1 << 0),
HID_INPUT_CAPABILITY_POINTER = (1 << 1),
HID_INPUT_CAPABILITY_TOUCH = (1 << 2),
HID_INPUT_CAPABILITY_TABLET = (1 << 3),
};
enum eHIDType {
enum eHIDType : uint8_t {
HID_TYPE_UNKNOWN = 0,
HID_TYPE_POINTER,
HID_TYPE_KEYBOARD,
@@ -27,7 +27,7 @@ enum eHIDType {
*/
class IHID {
public:
virtual ~IHID() {}
virtual ~IHID() = default;
virtual uint32_t getCapabilities() = 0;
virtual eHIDType getType();

View File

@@ -19,6 +19,7 @@ class IPointer : public IHID {
struct SMotionEvent {
uint32_t timeMs = 0;
Vector2D delta, unaccel;
bool mouse = false;
};
struct SMotionAbsoluteEvent {
@@ -31,6 +32,7 @@ class IPointer : public IHID {
uint32_t timeMs = 0;
uint32_t button = 0;
wl_pointer_button_state state = WL_POINTER_BUTTON_STATE_PRESSED;
bool mouse = false;
};
struct SAxisEvent {
@@ -40,6 +42,7 @@ class IPointer : public IHID {
wl_pointer_axis_relative_direction relativeDirection = WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL;
double delta = 0.0;
int32_t deltaDiscrete = 0;
bool mouse = false;
};
struct SSwipeBeginEvent {

View File

@@ -26,6 +26,7 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.timeMs = E.timeMs,
.delta = E.delta,
.unaccel = E.unaccel,
.mouse = true,
});
});
@@ -46,6 +47,7 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.timeMs = E.timeMs,
.button = E.button,
.state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
.mouse = true,
});
});
@@ -59,6 +61,7 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
.relativeDirection = (wl_pointer_axis_relative_direction)E.direction,
.delta = E.delta,
.deltaDiscrete = E.discrete,
.mouse = true,
});
});

View File

@@ -3,7 +3,6 @@
#include "IHID.hpp"
#include "../macros.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/math/Math.hpp"
AQUAMARINE_FORWARD(ITablet);
AQUAMARINE_FORWARD(ITabletTool);
@@ -27,7 +26,7 @@ class CTablet : public IHID {
virtual eHIDType getType();
SP<Aquamarine::ITablet> aq();
enum eTabletToolAxes {
enum eTabletToolAxes : uint16_t {
HID_TABLET_TOOL_AXIS_X = (1 << 0),
HID_TABLET_TOOL_AXIS_Y = (1 << 1),
HID_TABLET_TOOL_AXIS_TILT_X = (1 << 2),
@@ -92,9 +91,10 @@ class CTablet : public IHID {
WP<CTablet> self;
bool relativeInput = false;
bool absolutePos = false;
std::string boundOutput = "";
CBox activeArea;
CBox boundBox; // output-local
CBox boundBox;
private:
CTablet(SP<Aquamarine::ITablet> tablet);
@@ -172,7 +172,7 @@ class CTabletTool : public IHID {
static SP<CTabletTool> create(SP<Aquamarine::ITabletTool> tool);
~CTabletTool();
enum eTabletToolType {
enum eTabletToolType : uint8_t {
HID_TABLET_TOOL_TYPE_PEN = 1,
HID_TABLET_TOOL_TYPE_ERASER,
HID_TABLET_TOOL_TYPE_BRUSH,
@@ -183,7 +183,7 @@ class CTabletTool : public IHID {
HID_TABLET_TOOL_TYPE_TOTEM,
};
enum eTabletToolCapabilities {
enum eTabletToolCapabilities : uint8_t {
HID_TABLET_TOOL_CAPABILITY_TILT = (1 << 0),
HID_TABLET_TOOL_CAPABILITY_PRESSURE = (1 << 1),
HID_TABLET_TOOL_CAPABILITY_DISTANCE = (1 << 2),

View File

@@ -38,7 +38,7 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); });
listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); });
boundOutput = resource->boundOutput ? resource->boundOutput->szName : "entire";
boundOutput = resource->boundOutput ? resource->boundOutput->szName : "";
deviceName = pointer->name;
}

View File

@@ -1,12 +1,7 @@
#pragma once
#include "../defines.hpp"
//
// LISTEN_NAME -> the wl_listener
//
// LISTENER_NAME -> the wl_listener.notify function
//
// NOLINTNEXTLINE(readability-identifier-naming)
namespace Events {
// Window events
DYNLISTENFUNC(commitWindow);

View File

@@ -134,149 +134,178 @@ void Events::listener_mapWindow(void* owner, void* data) {
// window rules
PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
std::optional<eFullscreenMode> requestedInternalFSMode, requestedClientFSMode;
std::optional<sFullscreenState> requestedFSState;
std::optional<SFullscreenState> requestedFSState;
if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen))
requestedClientFSMode = FSMODE_FULLSCREEN;
for (auto const& r : PWINDOW->m_vMatchedRules) {
if (r.szRule.starts_with("monitor")) {
try {
const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' ')));
switch (r->ruleType) {
case CWindowRule::RULE_MONITOR: {
try {
const auto MONITORSTR = trim(r->szRule.substr(r->szRule.find(' ')));
if (MONITORSTR == "unset") {
PWINDOW->m_pMonitor = PMONITOR;
} else {
if (isNumber(MONITORSTR)) {
const MONITORID MONITOR = std::stoi(MONITORSTR);
if (const auto PM = g_pCompositor->getMonitorFromID(MONITOR); PM)
PWINDOW->m_pMonitor = PM;
else
PWINDOW->m_pMonitor = g_pCompositor->m_vMonitors.at(0);
if (MONITORSTR == "unset") {
PWINDOW->m_pMonitor = PMONITOR;
} else {
const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR);
if (PMONITOR)
PWINDOW->m_pMonitor = PMONITOR;
else {
Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
continue;
if (isNumber(MONITORSTR)) {
const MONITORID MONITOR = std::stoi(MONITORSTR);
if (const auto PM = g_pCompositor->getMonitorFromID(MONITOR); PM)
PWINDOW->m_pMonitor = PM;
else
PWINDOW->m_pMonitor = g_pCompositor->m_vMonitors.at(0);
} else {
const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR);
if (PMONITOR)
PWINDOW->m_pMonitor = PMONITOR;
else {
Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR);
continue;
}
}
}
const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock();
if (PWINDOW->m_pMonitor != PMONITOR) {
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID()));
PMONITOR = PMONITORFROMID;
}
PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
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()); }
break;
}
case CWindowRule::RULE_WORKSPACE: {
// check if it isnt unset
const auto WORKSPACERQ = r->szRule.substr(r->szRule.find_first_of(' ') + 1);
if (WORKSPACERQ == "unset") {
requestedWorkspace = "";
} else {
requestedWorkspace = WORKSPACERQ;
}
const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock();
const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ;
if (PWINDOW->m_pMonitor != PMONITOR) {
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID()));
PMONITOR = PMONITORFROMID;
if (JUSTWORKSPACE == PWORKSPACE->m_szName || JUSTWORKSPACE == "name:" + PWORKSPACE->m_szName)
requestedWorkspace = "";
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r->szValue);
break;
}
case CWindowRule::RULE_FLOAT: {
PWINDOW->m_bIsFloating = true;
break;
}
case CWindowRule::RULE_TILE: {
PWINDOW->m_bIsFloating = false;
break;
}
case CWindowRule::RULE_PSEUDO: {
PWINDOW->m_bIsPseudotiled = true;
break;
}
case CWindowRule::RULE_NOINITIALFOCUS: {
PWINDOW->m_bNoInitialFocus = true;
break;
}
case CWindowRule::RULE_FULLSCREENSTATE: {
const auto ARGS = CVarList(r->szRule.substr(r->szRule.find_first_of(' ') + 1), 2, ' ');
int internalMode, clientMode;
try {
internalMode = std::stoi(ARGS[0]);
} catch (std::exception& e) { internalMode = 0; }
try {
clientMode = std::stoi(ARGS[1]);
} catch (std::exception& e) { clientMode = 0; }
requestedFSState = SFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode};
break;
}
case CWindowRule::RULE_SUPPRESSEVENT: {
CVarList vars(r->szRule, 0, 's', true);
for (size_t i = 1; i < vars.size(); ++i) {
if (vars[i] == "fullscreen")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN;
else if (vars[i] == "maximize")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_MAXIMIZE;
else if (vars[i] == "activate")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
else if (vars[i] == "activatefocus")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
else
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
}
PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
} else if (r.szRule.starts_with("workspace")) {
// check if it isnt unset
const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (WORKSPACERQ == "unset") {
requestedWorkspace = "";
} else {
requestedWorkspace = WORKSPACERQ;
break;
}
const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ;
if (JUSTWORKSPACE == PWORKSPACE->m_szName || JUSTWORKSPACE == "name:" + PWORKSPACE->m_szName)
requestedWorkspace = "";
Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r.szValue);
} else if (r.szRule.starts_with("float")) {
PWINDOW->m_bIsFloating = true;
} else if (r.szRule.starts_with("tile")) {
PWINDOW->m_bIsFloating = false;
} else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.starts_with("fullscreenstate")) {
const auto ARGS = CVarList(r.szRule.substr(r.szRule.find_first_of(' ') + 1), 2, ' ');
int internalMode, clientMode;
try {
internalMode = std::stoi(ARGS[0]);
} catch (std::exception& e) { internalMode = 0; }
try {
clientMode = std::stoi(ARGS[1]);
} catch (std::exception& e) { clientMode = 0; }
requestedFSState = sFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode};
} else if (r.szRule.starts_with("suppressevent")) {
CVarList vars(r.szRule, 0, 's', true);
for (size_t i = 1; i < vars.size(); ++i) {
if (vars[i] == "fullscreen")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN;
else if (vars[i] == "maximize")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_MAXIMIZE;
else if (vars[i] == "activate")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
else if (vars[i] == "activatefocus")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
else
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
case CWindowRule::RULE_PIN: {
PWINDOW->m_bPinned = true;
break;
}
} else if (r.szRule == "pin") {
PWINDOW->m_bPinned = true;
} else if (r.szRule == "fullscreen") {
requestedInternalFSMode = FSMODE_FULLSCREEN;
} else if (r.szRule == "maximize") {
requestedInternalFSMode = FSMODE_MAXIMIZED;
} else if (r.szRule == "stayfocused") {
PWINDOW->m_bStayFocused = true;
} else if (r.szRule.starts_with("group")) {
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
continue;
// `group` is a shorthand of `group set`
if (trim(r.szRule) == "group") {
PWINDOW->m_eGroupRules |= GROUP_SET;
continue;
case CWindowRule::RULE_FULLSCREEN: {
requestedInternalFSMode = FSMODE_FULLSCREEN;
break;
}
CVarList vars(r.szRule, 0, 's');
std::string vPrev = "";
for (auto const& v : vars) {
if (v == "group")
case CWindowRule::RULE_MAXIMIZE: {
requestedInternalFSMode = FSMODE_MAXIMIZED;
break;
}
case CWindowRule::RULE_STAYFOCUSED: {
PWINDOW->m_bStayFocused = true;
break;
}
case CWindowRule::RULE_GROUP: {
if (PWINDOW->m_eGroupRules & GROUP_OVERRIDE)
continue;
if (v == "set") {
// `group` is a shorthand of `group set`
if (trim(r->szRule) == "group") {
PWINDOW->m_eGroupRules |= GROUP_SET;
} else if (v == "new") {
// shorthand for `group barred set`
PWINDOW->m_eGroupRules |= (GROUP_SET | GROUP_BARRED);
} else if (v == "lock") {
PWINDOW->m_eGroupRules |= GROUP_LOCK;
} else if (v == "invade") {
PWINDOW->m_eGroupRules |= GROUP_INVADE;
} else if (v == "barred") {
PWINDOW->m_eGroupRules |= GROUP_BARRED;
} else if (v == "deny") {
PWINDOW->m_sGroupData.deny = true;
} else if (v == "override") {
// Clear existing rules
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
} else if (v == "unset") {
// Clear existing rules and stop processing
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
break;
} else if (v == "always") {
if (vPrev == "set" || vPrev == "group")
PWINDOW->m_eGroupRules |= GROUP_SET_ALWAYS;
else if (vPrev == "lock")
PWINDOW->m_eGroupRules |= GROUP_LOCK_ALWAYS;
else
Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev);
continue;
}
vPrev = v;
CVarList vars(r->szRule, 0, 's');
std::string vPrev = "";
for (auto const& v : vars) {
if (v == "group")
continue;
if (v == "set") {
PWINDOW->m_eGroupRules |= GROUP_SET;
} else if (v == "new") {
// shorthand for `group barred set`
PWINDOW->m_eGroupRules |= (GROUP_SET | GROUP_BARRED);
} else if (v == "lock") {
PWINDOW->m_eGroupRules |= GROUP_LOCK;
} else if (v == "invade") {
PWINDOW->m_eGroupRules |= GROUP_INVADE;
} else if (v == "barred") {
PWINDOW->m_eGroupRules |= GROUP_BARRED;
} else if (v == "deny") {
PWINDOW->m_sGroupData.deny = true;
} else if (v == "override") {
// Clear existing rules
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
} else if (v == "unset") {
// Clear existing rules and stop processing
PWINDOW->m_eGroupRules = GROUP_OVERRIDE;
break;
} else if (v == "always") {
if (vPrev == "set" || vPrev == "group")
PWINDOW->m_eGroupRules |= GROUP_SET_ALWAYS;
else if (vPrev == "lock")
PWINDOW->m_eGroupRules |= GROUP_LOCK_ALWAYS;
else
Debug::log(ERR, "windowrule `group` does not support `{} always`", vPrev);
}
vPrev = v;
}
break;
}
default: break;
}
PWINDOW->applyDynamicRule(r);
}
@@ -296,7 +325,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID);
if (!pWorkspace)
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->monitorID(), requestedWorkspaceName);
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->monitorID(), requestedWorkspaceName, false);
PWORKSPACE = pWorkspace;
@@ -330,125 +359,133 @@ void Events::listener_mapWindow(void* owner, void* data) {
// size and move rules
for (auto const& r : PWINDOW->m_vMatchedRules) {
if (r.szRule.starts_with("size")) {
try {
switch (r->ruleType) {
case CWindowRule::RULE_SIZE: {
try {
auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) {
if (VALUE.starts_with('<'))
return std::min(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
else if (VALUE.starts_with('>'))
return std::max(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) {
if (VALUE.starts_with('<'))
return std::min(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
else if (VALUE.starts_with('>'))
return std::max(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL));
return stringToPercentage(VALUE, REL);
};
return stringToPercentage(VALUE, REL);
};
const auto VALUE = r->szRule.substr(r->szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto MAXSIZE = PWINDOW->requestedMaxSize();
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW);
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) :
stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x);
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) :
stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x);
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) :
stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y);
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) :
stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y);
Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY});
PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY});
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->szRule, r->szValue); }
break;
}
case CWindowRule::RULE_MOVE: {
try {
auto value = r->szRule.substr(r->szRule.find(' ') + 1);
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("move")) {
try {
auto value = r.szRule.substr(r.szRule.find(' ') + 1);
const bool ONSCREEN = value.starts_with("onscreen");
const bool ONSCREEN = value.starts_with("onscreen");
if (ONSCREEN)
value = value.substr(value.find_first_of(' ') + 1);
if (ONSCREEN)
value = value.substr(value.find_first_of(' ') + 1);
const bool CURSOR = value.starts_with("cursor");
if (CURSOR)
value = value.substr(value.find_first_of(' ') + 1);
const auto POSXSTR = value.substr(0, value.find(' '));
const auto POSYSTR = value.substr(value.find(' ') + 1);
int posX = 0;
int posY = 0;
if (POSXSTR.starts_with("100%-")) {
const bool subtractWindow = POSXSTR.starts_with("100%-w-");
const auto POSXRAW = (subtractWindow) ? POSXSTR.substr(7) : 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);
if (subtractWindow)
posX -= PWINDOW->m_vRealSize.goal().x;
const bool CURSOR = value.starts_with("cursor");
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
} else {
// cursor
if (POSXSTR == "cursor") {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
value = value.substr(value.find_first_of(' ') + 1);
const auto POSXSTR = value.substr(0, value.find(' '));
const auto POSYSTR = value.substr(value.find(' ') + 1);
int posX = 0;
int posY = 0;
if (POSXSTR.starts_with("100%-")) {
const bool subtractWindow = POSXSTR.starts_with("100%-w-");
const auto POSXRAW = (subtractWindow) ? POSXSTR.substr(7) : 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);
if (subtractWindow)
posX -= PWINDOW->m_vRealSize.goal().x;
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
posX = !POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x;
} else {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
// cursor
if (POSXSTR == "cursor") {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
} else {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
}
}
}
if (POSYSTR.starts_with("100%-")) {
const bool subtractWindow = POSYSTR.starts_with("100%-w-");
const auto POSYRAW = (subtractWindow) ? POSYSTR.substr(7) : 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);
if (POSYSTR.starts_with("100%-")) {
const bool subtractWindow = POSYSTR.starts_with("100%-w-");
const auto POSYRAW = (subtractWindow) ? POSYSTR.substr(7) : 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);
if (subtractWindow)
posY -= PWINDOW->m_vRealSize.goal().y;
if (subtractWindow)
posY -= PWINDOW->m_vRealSize.goal().y;
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
} else {
// cursor
if (POSYSTR == "cursor") {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
if (CURSOR)
Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!");
} else if (!CURSOR) {
posY = !POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y;
} else {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
// cursor
if (POSYSTR == "cursor") {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
} else {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
}
}
}
if (ONSCREEN) {
int borderSize = PWINDOW->getRealBorderSize();
if (ONSCREEN) {
int borderSize = PWINDOW->getRealBorderSize();
posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize));
posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize));
posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize));
}
posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize));
}
Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition;
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("center")) {
auto RESERVEDOFFSET = Vector2D();
const auto ARGS = CVarList(r.szRule, 2, ' ');
if (ARGS[1] == "1")
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r->szRule, r->szValue); }
break;
}
case CWindowRule::RULE_CENTER: {
auto RESERVEDOFFSET = Vector2D();
const auto ARGS = CVarList(r->szRule, 2, ' ');
if (ARGS[1] == "1")
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET;
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET;
break;
}
default: break;
}
}
@@ -463,26 +500,27 @@ void Events::listener_mapWindow(void* owner, void* data) {
bool setPseudo = false;
for (auto const& r : PWINDOW->m_vMatchedRules) {
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(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
if (r->ruleType != CWindowRule::RULE_SIZE)
continue;
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW);
try {
const auto VALUE = r->szRule.substr(r->szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x);
const auto MAXSIZE = PWINDOW->requestedMaxSize();
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : stringToPercentage(SIZEYSTR, PMONITOR->vecSize.y);
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x);
Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW);
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : stringToPercentage(SIZEYSTR, PMONITOR->vecSize.y);
setPseudo = true;
PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY);
Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW);
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
}
setPseudo = true;
PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY);
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->szRule, r->szValue); }
}
if (!setPseudo)
@@ -509,7 +547,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
else if (*PNEWTAKESOVERFS == 1)
requestedInternalFSMode = PWINDOW->m_pWorkspace->m_efFullscreenMode;
else if (*PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE);
g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE);
}
if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus &&
@@ -531,7 +569,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!PWINDOW->m_bNoInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) {
// fix fullscreen on requested (basically do a switcheroo)
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow)
g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE);
g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE);
PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealSize.warp();
@@ -539,7 +577,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE);
g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value());
} else if (requestedInternalFSMode.has_value() && requestedClientFSMode.has_value() && !PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = requestedInternalFSMode.value(), .client = requestedClientFSMode.value()});
g_pCompositor->setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = requestedInternalFSMode.value(), .client = requestedClientFSMode.value()});
else if (requestedInternalFSMode.has_value())
g_pCompositor->setWindowFullscreenInternal(PWINDOW, requestedInternalFSMode.value());
else if (requestedClientFSMode.has_value())
@@ -603,7 +641,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
// fix some xwayland apps that don't behave nicely
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID());
if (PWINDOW->m_pWorkspace)
PWINDOW->m_pWorkspace->updateWindows();
if (PMONITOR && PWINDOW->isX11OverrideRedirect())
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
@@ -699,7 +738,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pCompositor->setWindowFullscreenInternal(PWINDOWCANDIDATE, CURRENTFSMODE);
}
if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0)
if (!PWINDOWCANDIDATE && PWINDOW->m_pWorkspace && PWINDOW->m_pWorkspace->getWindows() == 0)
g_pInputManager->refocus();
g_pInputManager->sendMotionEventsToFocused();
@@ -729,7 +768,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pInputManager->recheckIdleInhibitorStatus();
// force report all sizes (QT sometimes has an issue with this)
g_pCompositor->forceReportSizesToWindowsOnWorkspace(PWINDOW->workspaceID());
if (PWINDOW->m_pWorkspace)
PWINDOW->m_pWorkspace->forceReportSizesToWindows();
// update lastwindow after focus
PWINDOW->onUnmap();
@@ -753,8 +793,8 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
if (!PWINDOW->m_bIsX11 && !PWINDOW->isFullscreen() && PWINDOW->m_bIsFloating) {
const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize;
const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize;
const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->layoutMinSize();
const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->layoutMaxSize();
PWINDOW->clampWindowSize(MINSIZE, MAXSIZE > Vector2D{1, 1} ? std::optional<Vector2D>{MAXSIZE} : std::nullopt);
g_pHyprRenderer->damageWindow(PWINDOW);

View File

@@ -2,11 +2,11 @@
#include "../managers/AnimationManager.hpp"
#include "../config/ConfigManager.hpp"
CBaseAnimatedVariable::CBaseAnimatedVariable(ANIMATEDVARTYPE type) : m_Type(type) {
CBaseAnimatedVariable::CBaseAnimatedVariable(eAnimatedVarType type) : m_Type(type) {
; // dummy var
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, AVARDAMAGEPOLICY policy) {
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pWindow = pWindow;
@@ -14,7 +14,7 @@ void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWIN
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, AVARDAMAGEPOLICY policy) {
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pLayer = pLayer;
@@ -22,7 +22,7 @@ void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy) {
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pWorkspace = pWorkspace;
@@ -30,7 +30,7 @@ void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWOR
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy) {
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;

View File

@@ -10,38 +10,39 @@
#include "../debug/Log.hpp"
#include "../desktop/DesktopTypes.hpp"
enum ANIMATEDVARTYPE {
enum eAnimatedVarType : int8_t {
AVARTYPE_INVALID = -1,
AVARTYPE_FLOAT,
AVARTYPE_VECTOR,
AVARTYPE_COLOR
};
// Utility to bind a type with its corresponding ANIMATEDVARTYPE
// Utility to bind a type with its corresponding eAnimatedVarType
template <class T>
struct typeToANIMATEDVARTYPE_t {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_INVALID;
// NOLINTNEXTLINE(readability-identifier-naming)
struct STypeToAnimatedVarType_t {
static constexpr eAnimatedVarType value = AVARTYPE_INVALID;
};
template <>
struct typeToANIMATEDVARTYPE_t<float> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_FLOAT;
struct STypeToAnimatedVarType_t<float> {
static constexpr eAnimatedVarType value = AVARTYPE_FLOAT;
};
template <>
struct typeToANIMATEDVARTYPE_t<Vector2D> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_VECTOR;
struct STypeToAnimatedVarType_t<Vector2D> {
static constexpr eAnimatedVarType value = AVARTYPE_VECTOR;
};
template <>
struct typeToANIMATEDVARTYPE_t<CColor> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_COLOR;
struct STypeToAnimatedVarType_t<CHyprColor> {
static constexpr eAnimatedVarType value = AVARTYPE_COLOR;
};
template <class T>
inline constexpr ANIMATEDVARTYPE typeToANIMATEDVARTYPE = typeToANIMATEDVARTYPE_t<T>::value;
inline constexpr eAnimatedVarType typeToeAnimatedVarType = STypeToAnimatedVarType_t<T>::value;
enum AVARDAMAGEPOLICY {
enum eAVarDamagePolicy : int8_t {
AVARDAMAGE_NONE = -1,
AVARDAMAGE_ENTIRE = 0,
AVARDAMAGE_BORDER,
@@ -63,15 +64,15 @@ concept OneOf = (... or std::same_as<T, U>);
// This is mainly to get better errors if we put a type that's not supported
// Otherwise template errors are ugly
template <class T>
concept Animable = OneOf<T, Vector2D, float, CColor>;
concept Animable = OneOf<T, Vector2D, float, CHyprColor>;
class CBaseAnimatedVariable {
public:
CBaseAnimatedVariable(ANIMATEDVARTYPE type);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy);
CBaseAnimatedVariable(eAnimatedVarType type);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy);
void create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy);
CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
@@ -103,7 +104,7 @@ class CBaseAnimatedVariable {
float getCurveValue();
// checks if an animation is in progress
inline bool isBeingAnimated() {
bool isBeingAnimated() const {
return m_bIsBeingAnimated;
}
@@ -111,7 +112,7 @@ class CBaseAnimatedVariable {
if an animation is not running, runs instantly.
if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnEnd(std::function<void(void* thisptr)> func, bool remove = true) {
m_fEndCallback = func;
m_fEndCallback = std::move(func);
m_bRemoveEndAfterRan = remove;
if (!isBeingAnimated())
@@ -121,14 +122,14 @@ class CBaseAnimatedVariable {
/* sets a function to be ran when an animation is started.
if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnBegin(std::function<void(void* thisptr)> func, bool remove = true) {
m_fBeginCallback = func;
m_fBeginCallback = std::move(func);
m_bRemoveBeginAfterRan = remove;
}
/* Sets the update callback, called every time the value is animated and a step is done
Warning: calling unregisterVar/registerVar in this handler will cause UB */
void setUpdateCallback(std::function<void(void* thisptr)> func) {
m_fUpdateCallback = func;
m_fUpdateCallback = std::move(func);
}
/* resets all callbacks. Does not call any. */
@@ -157,8 +158,8 @@ class CBaseAnimatedVariable {
std::chrono::steady_clock::time_point animationBegin;
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE;
ANIMATEDVARTYPE m_Type;
eAVarDamagePolicy m_eDamagePolicy = AVARDAMAGE_NONE;
eAnimatedVarType m_Type;
bool m_bRemoveEndAfterRan = true;
bool m_bRemoveBeginAfterRan = true;
@@ -206,24 +207,26 @@ class CBaseAnimatedVariable {
template <Animable VarType>
class CAnimatedVariable : public CBaseAnimatedVariable {
public:
CAnimatedVariable() : CBaseAnimatedVariable(typeToANIMATEDVARTYPE<VarType>) {} // dummy var
CAnimatedVariable() : CBaseAnimatedVariable(typeToeAnimatedVarType<VarType>) {
;
} // dummy var
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, AVARDAMAGEPOLICY policy) {
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) {
create(pAnimConfig, pWindow, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, AVARDAMAGEPOLICY policy) {
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) {
create(pAnimConfig, pLayer, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy) {
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) {
create(pAnimConfig, pWorkspace, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy) {
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) {
create(pAnimConfig, policy);
m_Value = value;
m_Goal = value;

View File

@@ -6,24 +6,27 @@
#include <algorithm>
void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
m_dPoints.clear();
const auto BEGIN = std::chrono::high_resolution_clock::now();
m_dPoints.emplace_back(Vector2D(0, 0));
for (auto const& p : *pVec) {
m_dPoints.push_back(p);
// Avoid reallocations by reserving enough memory upfront
m_vPoints.resize(pVec->size() + 2);
m_vPoints[0] = Vector2D(0, 0); // Start point
size_t index = 1; // Start after the first element
for (const auto& vec : *pVec) {
if (index < m_vPoints.size() - 1) { // Bounds check to ensure safety
m_vPoints[index] = vec;
++index;
}
}
m_vPoints.back() = Vector2D(1, 1); // End point
m_dPoints.emplace_back(Vector2D(1, 1));
RASSERT(m_dPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_dPoints.size());
RASSERT(m_vPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_vPoints.size());
// bake BAKEDPOINTS points for faster lookups
// T -> X ( / BAKEDPOINTS )
for (int i = 0; i < BAKEDPOINTS; ++i) {
m_aPointsBaked[i] = Vector2D(getXForT((i + 1) / (float)BAKEDPOINTS), getYForT((i + 1) / (float)BAKEDPOINTS));
float const t = (i + 1) / (float)BAKEDPOINTS;
m_aPointsBaked[i] = Vector2D(getXForT(t), getYForT(t));
}
const auto ELAPSEDUS = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGIN).count() / 1000.f;
@@ -40,18 +43,26 @@ void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
ELAPSEDUS, ELAPSEDCALCAVG);
}
float CBezierCurve::getYForT(float t) {
return 3 * t * pow(1 - t, 2) * m_dPoints[1].y + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].y + pow(t, 3);
float CBezierCurve::getXForT(float const& t) const {
float t2 = t * t;
float t3 = t2 * t;
return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].x + 3 * t2 * (1 - t) * m_vPoints[2].x + t3 * m_vPoints[3].x;
}
float CBezierCurve::getXForT(float t) {
return 3 * t * pow(1 - t, 2) * m_dPoints[1].x + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].x + pow(t, 3);
float CBezierCurve::getYForT(float const& t) const {
float t2 = t * t;
float t3 = t2 * t;
return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].y + 3 * t2 * (1 - t) * m_vPoints[2].y + t3 * m_vPoints[3].y;
}
// Todo: this probably can be done better and faster
float CBezierCurve::getYForPoint(float x) {
float CBezierCurve::getYForPoint(float const& x) const {
if (x >= 1.f)
return 1.f;
if (x <= 0.f)
return 0.f;
int index = 0;
bool below = true;

View File

@@ -1,6 +1,6 @@
#pragma once
#include <deque>
#include <vector>
#include <array>
#include <vector>
#include "math/Math.hpp"
@@ -16,13 +16,13 @@ class CBezierCurve {
// this EXCLUDES the 0,0 and 1,1 points,
void setup(std::vector<Vector2D>* points);
float getYForT(float t);
float getXForT(float t);
float getYForPoint(float x);
float getYForT(float const& t) const;
float getXForT(float const& t) const;
float getYForPoint(float const& x) const;
private:
// this INCLUDES the 0,0 and 1,1 points.
std::deque<Vector2D> m_dPoints;
std::vector<Vector2D> m_vPoints;
std::array<Vector2D, BAKEDPOINTS> m_aPointsBaked;
};

View File

@@ -30,25 +30,27 @@ constexpr LD operator""_TB(const LD BYTES) {
return BYTES * 1024 * 1024 * 1024 * 1024;
}
//NOLINTBEGIN
template <typename T>
using __acceptable_byte_operation_type = typename std::enable_if<std::is_trivially_constructible<T, ULL>::value || std::is_trivially_constructible<T, LD>::value>::type;
using internal_hl_acceptable_byte_operation_type = typename std::enable_if<std::is_trivially_constructible<T, ULL>::value || std::is_trivially_constructible<T, LD>::value>::type;
template <typename X, typename = __acceptable_byte_operation_type<X>>
template <typename X, typename = internal_hl_acceptable_byte_operation_type<X>>
constexpr X kBtoBytes(const X kB) {
return kB * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
template <typename X, typename = internal_hl_acceptable_byte_operation_type<X>>
constexpr X MBtoBytes(const X MB) {
return MB * 1024 * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
template <typename X, typename = internal_hl_acceptable_byte_operation_type<X>>
constexpr X GBtoBytes(const X GB) {
return GB * 1024 * 1024 * 1024;
}
template <typename X, typename = __acceptable_byte_operation_type<X>>
template <typename X, typename = internal_hl_acceptable_byte_operation_type<X>>
constexpr X TBtoBytes(const X TB) {
return TB * 1024 * 1024 * 1024 * 1024;
}
//NOLINTEND
#undef ULL
#undef LD

View File

@@ -5,22 +5,41 @@
#define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0)
#define BLUE(c) ((double)(((c)) & 0xff) / 255.0)
CColor::CColor() {}
CHyprColor::CHyprColor() = default;
CColor::CColor(float r, float g, float b, float a) {
this->r = r;
this->g = g;
this->b = b;
this->a = a;
CHyprColor::CHyprColor(float r_, float g_, float b_, float a_) : r(r_), g(g_), b(b_), a(a_) {
okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab();
}
CColor::CColor(uint64_t hex) {
this->r = RED(hex);
this->g = GREEN(hex);
this->b = BLUE(hex);
this->a = ALPHA(hex);
CHyprColor::CHyprColor(uint64_t hex) : r(RED(hex)), g(GREEN(hex)), b(BLUE(hex)), a(ALPHA(hex)) {
okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab();
}
uint32_t CColor::getAsHex() const {
CHyprColor::CHyprColor(const Hyprgraphics::CColor& color, float a_) : a(a_) {
const auto SRGB = color.asRgb();
r = SRGB.r;
g = SRGB.g;
b = SRGB.b;
okLab = color.asOkLab();
}
uint32_t CHyprColor::getAsHex() const {
return (uint32_t)(a * 255.f) * 0x1000000 + (uint32_t)(r * 255.f) * 0x10000 + (uint32_t)(g * 255.f) * 0x100 + (uint32_t)(b * 255.f) * 0x1;
}
}
Hyprgraphics::CColor::SSRGB CHyprColor::asRGB() const {
return {r, g, b};
}
Hyprgraphics::CColor::SOkLab CHyprColor::asOkLab() const {
return okLab;
}
Hyprgraphics::CColor::SHSL CHyprColor::asHSL() const {
return Hyprgraphics::CColor(okLab).asHSL();
}
CHyprColor CHyprColor::stripA() const {
return {r, g, b, 1.F};
}

View File

@@ -1,35 +1,47 @@
#pragma once
#include <cstdint>
#include <hyprgraphics/color/Color.hpp>
#include "../debug/Log.hpp"
#include "../macros.hpp"
class CColor {
class CHyprColor {
public:
CColor();
CColor(float r, float g, float b, float a);
CColor(uint64_t);
float r = 0, g = 0, b = 0, a = 1.f;
CHyprColor();
CHyprColor(float r, float g, float b, float a);
CHyprColor(const Hyprgraphics::CColor& col, float a);
CHyprColor(uint64_t);
// AR32
uint32_t getAsHex() const;
uint32_t getAsHex() const;
Hyprgraphics::CColor::SSRGB asRGB() const;
Hyprgraphics::CColor::SOkLab asOkLab() const;
Hyprgraphics::CColor::SHSL asHSL() const;
CHyprColor stripA() const;
CColor operator-(const CColor& c2) const {
return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a);
//
bool operator==(const CHyprColor& c2) const {
return c2.r == r && c2.g == g && c2.b == b && c2.a == a;
}
CColor operator+(const CColor& c2) const {
return CColor(r + c2.r, g + c2.g, b + c2.b, a + c2.a);
// stubs for the AnimationMgr
CHyprColor operator-(const CHyprColor& c2) const {
RASSERT(false, "CHyprColor: - is a STUB");
return {};
}
CColor operator*(const float& v) const {
return CColor(r * v, g * v, b * v, a * v);
CHyprColor operator+(const CHyprColor& c2) const {
RASSERT(false, "CHyprColor: + is a STUB");
return {};
}
bool operator==(const CColor& c2) const {
return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
CHyprColor operator*(const float& c2) const {
RASSERT(false, "CHyprColor: * is a STUB");
return {};
}
CColor stripA() const {
return {r, g, b, 1};
}
double r = 0, g = 0, b = 0, a = 0;
private:
Hyprgraphics::CColor::SOkLab okLab; // cache for the OkLab representation
};

View File

@@ -231,7 +231,7 @@ inline const std::vector<SPixelFormat> GLES3_FORMATS = {
},
};
SHMFormat FormatUtils::drmToShm(DRMFormat drm) {
SHMFormat NFormatUtils::drmToShm(DRMFormat drm) {
switch (drm) {
case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888;
case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888;
@@ -241,7 +241,7 @@ SHMFormat FormatUtils::drmToShm(DRMFormat drm) {
return drm;
}
DRMFormat FormatUtils::shmToDRM(SHMFormat shm) {
DRMFormat NFormatUtils::shmToDRM(SHMFormat shm) {
switch (shm) {
case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888;
case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888;
@@ -251,7 +251,7 @@ DRMFormat FormatUtils::shmToDRM(SHMFormat shm) {
return shm;
}
const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) {
const SPixelFormat* NFormatUtils::getPixelFormatFromDRM(DRMFormat drm) {
for (auto const& fmt : GLES3_FORMATS) {
if (fmt.drmFormat == drm)
return &fmt;
@@ -260,7 +260,7 @@ const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) {
return nullptr;
}
const SPixelFormat* FormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha) {
const SPixelFormat* NFormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha) {
for (auto const& fmt : GLES3_FORMATS) {
if (fmt.glFormat == (int)glFormat && fmt.glType == (int)glType && fmt.withAlpha == alpha)
return &fmt;
@@ -269,23 +269,23 @@ const SPixelFormat* FormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_
return nullptr;
}
bool FormatUtils::isFormatOpaque(DRMFormat drm) {
const auto FMT = FormatUtils::getPixelFormatFromDRM(drm);
bool NFormatUtils::isFormatOpaque(DRMFormat drm) {
const auto FMT = NFormatUtils::getPixelFormatFromDRM(drm);
if (!FMT)
return false;
return !FMT->withAlpha;
}
int FormatUtils::pixelsPerBlock(const SPixelFormat* const fmt) {
int NFormatUtils::pixelsPerBlock(const SPixelFormat* const fmt) {
return fmt->blockSize.x * fmt->blockSize.y > 0 ? fmt->blockSize.x * fmt->blockSize.y : 1;
}
int FormatUtils::minStride(const SPixelFormat* const fmt, int32_t width) {
int NFormatUtils::minStride(const SPixelFormat* const fmt, int32_t width) {
return std::ceil((width * fmt->bytesPerBlock) / pixelsPerBlock(fmt));
}
uint32_t FormatUtils::drmFormatToGL(DRMFormat drm) {
uint32_t NFormatUtils::drmFormatToGL(DRMFormat drm) {
switch (drm) {
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
@@ -302,7 +302,7 @@ uint32_t FormatUtils::drmFormatToGL(DRMFormat drm) {
return GL_RGBA;
}
uint32_t FormatUtils::glFormatToType(uint32_t gl) {
uint32_t NFormatUtils::glFormatToType(uint32_t gl) {
return gl != GL_RGBA ?
#ifdef GLES2
GL_UNSIGNED_INT_2_10_10_10_REV_EXT :
@@ -312,14 +312,14 @@ uint32_t FormatUtils::glFormatToType(uint32_t gl) {
GL_UNSIGNED_BYTE;
}
std::string FormatUtils::drmFormatName(DRMFormat drm) {
std::string NFormatUtils::drmFormatName(DRMFormat drm) {
auto n = drmGetFormatName(drm);
std::string name = n;
free(n);
return name;
}
std::string FormatUtils::drmModifierName(uint64_t mod) {
std::string NFormatUtils::drmModifierName(uint64_t mod) {
auto n = drmGetFormatModifierName(mod);
std::string name = n;
free(n);

View File

@@ -22,7 +22,7 @@ struct SPixelFormat {
typedef Aquamarine::SDRMFormat SDRMFormat;
namespace FormatUtils {
namespace NFormatUtils {
SHMFormat drmToShm(DRMFormat drm);
DRMFormat shmToDRM(SHMFormat shm);

View File

@@ -6,6 +6,7 @@
#include <optional>
#include <cstring>
#include <cmath>
#include <filesystem>
#include <set>
#include <sys/utsname.h>
#include <sys/mman.h>
@@ -17,7 +18,9 @@
#include <execinfo.h>
#endif
#include <hyprutils/string/String.hpp>
#include <hyprutils/os/Process.hpp>
using namespace Hyprutils::String;
using namespace Hyprutils::OS;
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sysctl.h>
@@ -261,7 +264,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
WORKSPACEID id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0;
while (++id < LONG_MAX) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) {
if (!invalidWSes.contains(id) && (!PWORKSPACE || PWORKSPACE->getWindows() == 0)) {
result.id = id;
return result;
}
@@ -583,18 +586,12 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve
// Execute a shell command and get the output
std::string execAndGet(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
using PcloseType = int (*)(FILE*);
const std::unique_ptr<FILE, PcloseType> pipe(popen(cmd, "r"), static_cast<PcloseType>(pclose));
if (!pipe) {
Debug::log(ERR, "execAndGet: failed in pipe");
return "";
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
CProcess proc("/bin/sh", {"-c", cmd});
if (!proc.runSync())
return "error";
return proc.stdOut();
}
void logSystemInfo() {
@@ -610,9 +607,26 @@ void logSystemInfo() {
Debug::log(NONE, "\n");
#if defined(__DragonFly__) || defined(__FreeBSD__)
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga");
#elif defined(__arm__) || defined(__aarch64__)
const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible");
std::string GPUINFO;
const std::filesystem::path dev_tree = "/proc/device-tree";
try {
if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) {
std::for_each(std::filesystem::directory_iterator(dev_tree), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& entry) {
if (std::filesystem::is_directory(entry) && entry.path().filename().string().starts_with("soc")) {
std::for_each(std::filesystem::directory_iterator(entry.path()), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& sub_entry) {
if (std::filesystem::is_directory(sub_entry) && sub_entry.path().filename().string().starts_with("gpu")) {
std::filesystem::path file_path = sub_entry.path() / "compatible";
std::ifstream file(file_path);
if (file)
GPUINFO.append(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
}
});
}
});
}
} catch (...) { GPUINFO = "error"; }
#else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif
@@ -677,44 +691,91 @@ int64_t getPPIDof(int64_t pid) {
#endif
}
int64_t configStringToInt(const std::string& VALUE) {
std::expected<int64_t, std::string> configStringToInt(const std::string& VALUE) {
auto parseHex = [](const std::string& value) -> std::expected<int64_t, std::string> {
try {
size_t position;
auto result = stoll(value, &position, 16);
if (position == value.size())
return result;
} catch (const std::exception&) {}
return std::unexpected("invalid hex " + value);
};
if (VALUE.starts_with("0x")) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
return stol(VALUEWITHOUTHEX, nullptr, 16);
return parseHex(VALUE);
} else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) {
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
const auto VALUEWITHOUTFUNC = trim(VALUE.substr(5, VALUE.length() - 6));
if (trim(VALUEWITHOUTFUNC).length() != 8) {
Debug::log(WARN, "invalid length {} for rgba", VALUEWITHOUTFUNC.length());
throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)");
// try doing it the comma way first
if (std::count(VALUEWITHOUTFUNC.begin(), VALUEWITHOUTFUNC.end(), ',') == 3) {
// cool
std::string rolling = VALUEWITHOUTFUNC;
auto r = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
auto g = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
auto b = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
uint8_t a = 0;
if (!r || !g || !b)
return std::unexpected("failed parsing " + VALUEWITHOUTFUNC);
try {
a = std::round(std::stof(trim(rolling.substr(0, rolling.find(',')))) * 255.f);
} catch (std::exception& e) { return std::unexpected("failed parsing " + VALUEWITHOUTFUNC); }
return a * (Hyprlang::INT)0x1000000 + *r * (Hyprlang::INT)0x10000 + *g * (Hyprlang::INT)0x100 + *b;
} else if (VALUEWITHOUTFUNC.length() == 8) {
const auto RGBA = parseHex(VALUEWITHOUTFUNC);
if (!RGBA)
return RGBA;
// now we need to RGBA -> ARGB. The config holds ARGB only.
return (*RGBA >> 8) + 0x1000000 * (*RGBA & 0xFF);
}
const auto RGBA = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
return std::unexpected("rgba() expects length of 8 characters (4 bytes) or 4 comma separated values");
// now we need to RGBA -> ARGB. The config holds ARGB only.
return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF);
} else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) {
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
const auto VALUEWITHOUTFUNC = trim(VALUE.substr(4, VALUE.length() - 5));
if (trim(VALUEWITHOUTFUNC).length() != 6) {
Debug::log(WARN, "invalid length {} for rgb", VALUEWITHOUTFUNC.length());
throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)");
// try doing it the comma way first
if (std::count(VALUEWITHOUTFUNC.begin(), VALUEWITHOUTFUNC.end(), ',') == 2) {
// cool
std::string rolling = VALUEWITHOUTFUNC;
auto r = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
auto g = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
rolling = rolling.substr(rolling.find(',') + 1);
auto b = configStringToInt(trim(rolling.substr(0, rolling.find(','))));
if (!r || !g || !b)
return std::unexpected("failed parsing " + VALUEWITHOUTFUNC);
return (Hyprlang::INT)0xFF000000 + *r * (Hyprlang::INT)0x10000 + *g * (Hyprlang::INT)0x100 + *b;
} else if (VALUEWITHOUTFUNC.length() == 6) {
auto r = parseHex(VALUEWITHOUTFUNC);
return r ? *r + 0xFF000000 : r;
}
const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16);
return RGB + 0xFF000000; // 0xFF for opaque
return std::unexpected("rgb() expects length of 6 characters (3 bytes) or 3 comma separated values");
} else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) {
return 1;
} else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) {
return 0;
}
if (VALUE.empty() || !isNumber(VALUE))
return 0;
if (VALUE.empty() || !isNumber(VALUE, false))
return std::unexpected("cannot parse \"" + VALUE + "\" as an int.");
return std::stoll(VALUE);
try {
const auto RES = std::stoll(VALUE);
return RES;
} catch (std::exception& e) { return std::unexpected(std::string{"stoll threw: "} + e.what()); }
return std::unexpected("parse error");
}
Vector2D configStringToVector2D(const std::string& VALUE) {
@@ -869,4 +930,31 @@ float stringToPercentage(const std::string& VALUE, const float REL) {
return (std::stof(VALUE.substr(0, VALUE.length() - 1)) * REL) / 100.f;
else
return std::stof(VALUE);
};
}
bool executableExistsInPath(const std::string& exe) {
if (!getenv("PATH"))
return false;
static CVarList paths(getenv("PATH"), 0, ':', true);
for (auto& p : paths) {
std::string path = p + std::string{"/"} + exe;
std::error_code ec;
if (!std::filesystem::exists(path, ec) || ec)
continue;
if (!std::filesystem::is_regular_file(path, ec) || ec)
continue;
auto stat = std::filesystem::status(path, ec);
if (ec)
continue;
auto perms = stat.permissions();
return std::filesystem::perms::none != (perms & std::filesystem::perms::others_exec);
}
return false;
}

View File

@@ -6,6 +6,7 @@
#include "math/Math.hpp"
#include <vector>
#include <format>
#include <expected>
#include "../SharedDefs.hpp"
#include "../macros.hpp"
@@ -19,28 +20,29 @@ struct SWorkspaceIDName {
std::string name;
};
std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
void removeWLSignal(wl_listener*);
std::string escapeJSONStrings(const std::string& str);
bool isDirection(const std::string&);
bool isDirection(const char&);
SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&);
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
void logSystemInfo();
std::string execAndGet(const char*);
int64_t getPPIDof(int64_t pid);
int64_t configStringToInt(const std::string&);
Vector2D configStringToVector2D(const std::string&);
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
double normalizeAngleRad(double ang);
std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err);
bool envEnabled(const std::string& env);
int allocateSHMFile(size_t len);
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr);
float stringToPercentage(const std::string& VALUE, const float REL);
std::string absolutePath(const std::string&, const std::string&);
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
void removeWLSignal(wl_listener*);
std::string escapeJSONStrings(const std::string& str);
bool isDirection(const std::string&);
bool isDirection(const char&);
SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&);
std::optional<std::string> cleanCmdForWorkspace(const std::string&, std::string);
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
void logSystemInfo();
std::string execAndGet(const char*);
int64_t getPPIDof(int64_t pid);
std::expected<int64_t, std::string> configStringToInt(const std::string&);
Vector2D configStringToVector2D(const std::string&);
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
double normalizeAngleRad(double ang);
std::vector<SCallstackFrameInfo> getBacktrace();
void throwError(const std::string& err);
bool envEnabled(const std::string& env);
int allocateSHMFile(size_t len);
bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr);
float stringToPercentage(const std::string& VALUE, const float REL);
bool executableExistsInPath(const std::string& exe);
template <typename... Args>
[[deprecated("use std::format instead")]] std::string getFormat(std::format_string<Args...> fmt, Args&&... args) {

View File

@@ -39,6 +39,7 @@ CMonitor::~CMonitor() {
}
void CMonitor::onConnect(bool noRule) {
EMIT_HOOK_EVENT("preMonitorAdded", self.lock());
CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }};
if (output->supportsExplicit) {
@@ -238,6 +239,7 @@ void CMonitor::onConnect(bool noRule) {
}
void CMonitor::onDisconnect(bool destroy) {
EMIT_HOOK_EVENT("preMonitorRemoved", self.lock());
CScopeGuard x = {[this]() {
if (g_pCompositor->m_bIsShuttingDown)
return;
@@ -312,7 +314,7 @@ void CMonitor::onDisconnect(bool destroy) {
g_pCompositor->warpCursorTo(BACKUPMON->vecPosition + BACKUPMON->vecTransformedSize / 2.F, true);
// move workspaces
std::deque<PHLWORKSPACE> wspToMove;
std::vector<PHLWORKSPACE> wspToMove;
for (auto const& w : g_pCompositor->m_vWorkspaces) {
if (w->m_pMonitor == self || !w->m_pMonitor)
wspToMove.push_back(w);
@@ -539,7 +541,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
}
// move all the WS
std::deque<PHLWORKSPACE> wspToMove;
std::vector<PHLWORKSPACE> wspToMove;
for (auto const& w : g_pCompositor->m_vWorkspaces) {
if (w->m_pMonitor == self || !w->m_pMonitor)
wspToMove.push_back(w);
@@ -627,17 +629,17 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo
if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace &&
!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
auto pWindow = pWorkspace->getLastFocusedWindow();
auto pWindow = pWorkspace->m_bHasFullscreenWindow ? pWorkspace->getFullscreenWindow() : pWorkspace->getLastFocusedWindow();
if (!pWindow) {
if (*PFOLLOWMOUSE == 1)
pWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!pWindow)
pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
pWindow = pWorkspace->getTopLeftWindow();
if (!pWindow)
pWindow = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID);
pWindow = pWorkspace->getFirstWindow();
}
g_pCompositor->focusWindow(pWindow);
@@ -1008,8 +1010,8 @@ void CMonitor::onMonitorFrame() {
g_pHyprRenderer->renderMonitor(self.lock());
}
CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) {
;
}
CMonitorState::~CMonitorState() {

View File

@@ -1,7 +1,7 @@
#pragma once
#include "../defines.hpp"
#include <deque>
#include <vector>
#include "WLClasses.hpp"
#include <vector>
#include <array>
@@ -16,7 +16,7 @@
#include <aquamarine/allocator/Swapchain.hpp>
// Enum for the different types of auto directions, e.g. auto-left, auto-up.
enum eAutoDirs {
enum eAutoDirs : uint8_t {
DIR_AUTO_NONE = 0, /* None will be treated as right. */
DIR_AUTO_UP,
DIR_AUTO_DOWN,

View File

@@ -4,59 +4,56 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <cerrno>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <stdlib.h>
#include <cstdlib>
#include <cstring>
namespace Systemd {
int SdBooted(void) {
if (!faccessat(AT_FDCWD, "/run/systemd/system/", F_OK, AT_SYMLINK_NOFOLLOW))
return true;
int NSystemd::sdBooted() {
if (!faccessat(AT_FDCWD, "/run/systemd/system/", F_OK, AT_SYMLINK_NOFOLLOW))
return true;
if (errno == ENOENT)
return false;
if (errno == ENOENT)
return false;
return -errno;
}
int SdNotify(int unsetEnvironment, const char* state) {
int fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
constexpr char envVar[] = "NOTIFY_SOCKET";
auto cleanup = [unsetEnvironment, envVar](int* fd) {
if (unsetEnvironment)
unsetenv(envVar);
close(*fd);
};
std::unique_ptr<int, decltype(cleanup)> fdCleaup(&fd, cleanup);
const char* addr = getenv(envVar);
if (!addr)
return 0;
// address length must be at most this; see man 7 unix
size_t addrLen = strnlen(addr, 107);
struct sockaddr_un unixAddr;
unixAddr.sun_family = AF_UNIX;
strncpy(unixAddr.sun_path, addr, addrLen);
if (unixAddr.sun_path[0] == '@')
unixAddr.sun_path[0] = '\0';
if (connect(fd, (const sockaddr*)&unixAddr, sizeof(struct sockaddr_un)) < 0)
return -errno;
// arbitrary value which seems to be enough for s-d messages
ssize_t stateLen = strnlen(state, 128);
if (write(fd, state, stateLen) == stateLen)
return 1;
return -errno;
}
return -errno;
}
int NSystemd::sdNotify(int unsetEnvironment, const char* state) {
int fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
constexpr char envVar[] = "NOTIFY_SOCKET";
auto cleanup = [unsetEnvironment, envVar](const int* fd) {
if (unsetEnvironment)
unsetenv(envVar);
close(*fd);
};
std::unique_ptr<int, decltype(cleanup)> fdCleaup(&fd, cleanup);
const char* addr = getenv(envVar);
if (!addr)
return 0;
// address length must be at most this; see man 7 unix
size_t addrLen = strnlen(addr, 107);
struct sockaddr_un unixAddr;
unixAddr.sun_family = AF_UNIX;
strncpy(unixAddr.sun_path, addr, addrLen);
if (unixAddr.sun_path[0] == '@')
unixAddr.sun_path[0] = '\0';
if (connect(fd, (const sockaddr*)&unixAddr, sizeof(struct sockaddr_un)) < 0)
return -errno;
// arbitrary value which seems to be enough for s-d messages
ssize_t stateLen = strnlen(state, 128);
if (write(fd, state, stateLen) == stateLen)
return 1;
return -errno;
}

View File

@@ -1,6 +1,6 @@
#pragma once
namespace Systemd {
int SdBooted(void);
int SdNotify(int unset_environment, const char* state);
namespace NSystemd {
int sdBooted(void);
int sdNotify(int unset_environment, const char* state);
}

View File

@@ -3,80 +3,135 @@
#include <vector>
#include <string>
inline const std::vector<std::string> SPLASHES = {
// clang-format off
"Woo, animations!",
"It's like Hypr, but better.",
"Release 1.0 when?",
"It's not awesome, it's Hyprland!",
"\"I commit too often, people can't catch up lmao\" - Vaxry",
"This text is random.",
"\"There are reasons to not use rust.\" - Boga",
"Read the wiki.",
"\"Hello everyone this is YOUR daily dose of read the wiki\" - Vaxry",
"h",
"\"why no work, bro I haven't hacked your pc to get live feeds yet\" - Vaxry",
"Compile, wait for 20 minutes, notice a new commit, compile again.",
"To rice, or not to rice, that is the question.",
"Now available on Fedora!",
"\"Hyprland is so good it starts with a capital letter\" - Hazel",
"\"please make this message a splash\" - eriedaberrie",
"\"the only wayland compositor powered by fried chicken\" - raf",
"\"This will never get into Hyprland\" - Flafy",
"\"Hyprland only gives you up on -git\" - fazzi",
"Segmentation fault (core dumped)",
"\"disabling hyprland logo is a war crime\" - vaxry",
"some basic startup code",
"\"I think I am addicted to hyprland\" - mathisbuilder",
"\"hyprland is the most important package in the arch repos\" - jacekpoz",
"Thanks Brodie!",
"Thanks fufexan!",
"Thanks raf!",
"You can't use --splash to change this message :)",
"Hyprland will overtake Gnome in popularity by [insert year]",
// music reference / quote section
"J'remue le ciel, le jour, la nuit.",
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
"Wir sind schon sehr lang zusammen...",
"I see a red door and I want it painted black.",
"Take on me, take me on...",
"You spin me right round baby right round",
"Stayin' alive, stayin' alive",
"Say no way, say no way ya, no way!",
"Ground control to Major Tom...",
"Alors on danse",
"And all that I can see, is just a yellow lemon tree.",
"Got a one-way ticket to the blues",
"Is this the real life, is this just fantasy",
"What's in your head, in your head?",
"We're all living in America, America, America.",
"I'm still standing, better than I ever did",
"Here comes the sun, bringing you love and shining on everyone",
"Two trailer park girls go round the outside",
"With the lights out, it's less dangerous",
"Here we go back, this is the moment, tonight is the night",
"Now you're just somebody that I used to know...",
"Black bird, black moon, black sky",
"Some legends are told, some turn to dust or to gold",
"Your brain gets smart, but your head gets dumb.",
"Save your mercy for someone who needs it more",
"You're gonna hear my voice when I shout it out loud",
"Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm",
"Súbeme la radio que esta es mi canción",
"I'm beggin', beggin' you",
"Never gonna let you down (I am trying!)",
"\"I use Arch, btw\" - John Cena",
"\"Hyper\".replace(\"e\", \"\")",
"\"my win11 install runs hyprland that is true\" - raf",
"\"stop playing league loser\" - hyprBot",
"\"If it ain't broke, don't fix it\" - Lucascito_03",
"\"@vaxry how do i learn c++\" - flicko",
//
"Join the discord server!",
"Thanks ThatOneCalculator!",
"The AUR packages always work, except for the times they don't.",
"Funny animation compositor woo",
//
"2 years!"
// clang-format on
namespace NSplashes {
inline const std::vector<std::string> SPLASHES = {
// clang-format off
"Woo, animations!",
"It's like Hypr, but better.",
"Release 1.0 when?",
"It's not awesome, it's Hyprland!",
"\"I commit too often, people can't catch up lmao\" - Vaxry",
"This text is random.",
"\"There are reasons to not use rust.\" - Boga",
"Read the wiki.",
"\"Hello everyone this is YOUR daily dose of read the wiki\" - Vaxry",
"h",
"\"why no work, bro I haven't hacked your pc to get live feeds yet\" - Vaxry",
"Compile, wait for 20 minutes, notice a new commit, compile again.",
"To rice, or not to rice, that is the question.",
"Now available on Fedora!",
"\"Hyprland is so good it starts with a capital letter\" - Hazel",
"\"please make this message a splash\" - eriedaberrie",
"\"the only wayland compositor powered by fried chicken\" - raf",
"\"This will never get into Hyprland\" - Flafy",
"\"Hyprland only gives you up on -git\" - fazzi",
"Segmentation fault (core dumped)",
"\"disabling hyprland logo is a war crime\" - vaxry",
"some basic startup code",
"\"I think I am addicted to hyprland\" - mathisbuilder",
"\"hyprland is the most important package in the arch repos\" - jacekpoz",
"Thanks Brodie!",
"Thanks fufexan!",
"Thanks raf!",
"You can't use --splash to change this message :)",
"Hyprland will overtake Gnome in popularity by [insert year]",
"Designed in California - Assembled in China",
"\"something <time here> and still no new splash\" - snowman",
"My name is Land. Hypr Land. One red bull, shaken not stirred.",
"\"Glory To The Emperor\" - raf",
"Help I forgot to install kitty",
"Go to settings to activate Hyprland",
"Why is there code??? Make a damn .exe file and give it to me.",
"Hyprland is not a window manager!",
"Can we get a version without anime girls?",
"Check out quickshell!",
"A day without Hyprland is a day wasted",
"By dt, do you mean damage tracking or distrotube?",
"Made in Poland",
"\"I use Arch, btw\" - John Cena",
"\"Hyper\".replace(\"e\", \"\")",
"\"my win11 install runs hyprland that is true\" - raf",
"\"stop playing league loser\" - hyprBot",
"\"If it ain't broke, don't fix it\" - Lucascito_03",
"\"@vaxry how do i learn c++\" - flicko",
"Join the discord server!",
"Thanks ThatOneCalculator!",
"The AUR packages always work, except for the times they don't.",
"Funny animation compositor woo",
"2 years!",
// music reference / quote section
"J'remue le ciel, le jour, la nuit.",
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
"Wir sind schon sehr lang zusammen...",
"I see a red door and I want it painted black.",
"Take on me, take me on...",
"You spin me right round baby right round",
"Stayin' alive, stayin' alive",
"Say no way, say no way ya, no way!",
"Ground control to Major Tom...",
"Alors on danse",
"And all that I can see, is just a yellow lemon tree.",
"Got a one-way ticket to the blues",
"Is this the real life, is this just fantasy",
"What's in your head, in your head?",
"We're all living in America, America, America.",
"I'm still standing, better than I ever did",
"Here comes the sun, bringing you love and shining on everyone",
"Two trailer park girls go round the outside",
"With the lights out, it's less dangerous",
"Here we go back, this is the moment, tonight is the night",
"Now you're just somebody that I used to know...",
"Black bird, black moon, black sky",
"Some legends are told, some turn to dust or to gold",
"Your brain gets smart, but your head gets dumb.",
"Save your mercy for someone who needs it more",
"You're gonna hear my voice when I shout it out loud",
"Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm",
"Súbeme la radio que esta es mi canción",
"I'm beggin', beggin' you",
"Never gonna let you down (I am trying!)",
"Hier kommt die Sonne",
"Kickstart my heart, give it a start",
"Fear of the dark, I have a constant fear that something's always near",
"Komm mit, reih dich ein.",
"I wish I had an angel for one moment of love",
"We're the children of the dark",
"You float like a feather, in a beautiful world",
"Demons come at night and they bring the end",
"All I wanna say is that they don't really care about us",
"Has he lost his mind? Can he see or is he blind?",
// clang-format on
};
inline const std::vector<std::string> SPLASHES_CHRISTMAS = {
// clang-format off
"Merry Christmas!",
"Merry Xmas!",
"Ho ho ho",
"Santa was here",
"Make sure to spend some jolly time with those near and dear to you!",
"Have you checked for christmas presents yet?",
// clang-format on
};
// ONLY valid near new years.
inline static int newYear = []() -> int {
auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto local = *localtime(&tt);
if (local.tm_mon < 8 /* decided with a fair die I promise. */)
return local.tm_year + 1900;
return local.tm_year + 1901;
}();
inline const std::vector<std::string> SPLASHES_NEWYEAR = {
// clang-format off
"Happy new Year!",
"[New year] will be the year of the Linux desktop!",
"[New year] will be the year of the Hyprland desktop!",
std::format("{} will be the year of the Linux desktop!", newYear),
std::format("{} will be the year of the Hyprland desktop!", newYear),
std::format("Let's make {} even better than {}!", newYear, newYear - 1),
// clang-format on
};
};

View File

@@ -5,11 +5,11 @@
class CTagKeeper {
public:
bool isTagged(const std::string& tag, bool strict = false);
bool applyTag(const std::string& tag, bool dynamic = false);
bool removeDynamicTags();
bool isTagged(const std::string& tag, bool strict = false);
bool applyTag(const std::string& tag, bool dynamic = false);
bool removeDynamicTags();
inline const auto& getTags() {
const auto& getTags() const {
return m_tags;
};

View File

@@ -1,5 +1,5 @@
#include "Watchdog.hpp"
#include <signal.h>
#include <csignal>
#include "config/ConfigManager.hpp"
#include "../config/ConfigValue.hpp"
@@ -12,8 +12,7 @@ CWatchdog::~CWatchdog() {
m_pWatchdog->join();
}
CWatchdog::CWatchdog() {
m_iMainThreadPID = pthread_self();
CWatchdog::CWatchdog() : m_iMainThreadPID(pthread_self()) {
m_pWatchdog = std::make_unique<std::thread>([this] {
static auto PTIMEOUT = CConfigValue<Hyprlang::INT>("debug:watchdog_timeout");
@@ -24,7 +23,7 @@ CWatchdog::CWatchdog() {
if (!m_bWillWatch)
m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified || m_bExitThread; });
else if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified || m_bExitThread; }) == false)
else if (!m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified || m_bExitThread; }))
pthread_kill(m_iMainThreadPID, SIGUSR1);
if (m_bExitThread)

View File

@@ -6,6 +6,7 @@
#include <hyprutils/math/Region.hpp>
#include <hyprutils/math/Mat3x3.hpp>
// NOLINTNEXTLINE
using namespace Hyprutils::Math;
eTransform wlTransformToHyprutils(wl_output_transform t);

View File

@@ -2,6 +2,7 @@
#include <hyprutils/memory/WeakPtr.hpp>
//NOLINTNEXTLINE
using namespace Hyprutils::Memory;
#define SP Hyprutils::Memory::CSharedPointer

View File

@@ -2,4 +2,5 @@
#include <hyprutils/signal/Signal.hpp>
//NOLINTNEXTLINE
using namespace Hyprutils::Signal;

View File

@@ -2,4 +2,5 @@
#include <hyprutils/string/VarList.hpp>
//NOLINTNEXTLINE
using namespace Hyprutils::String;

View File

@@ -33,7 +33,7 @@ CHyprError::~CHyprError() {
m_fFadeOpacity.unregister();
}
void CHyprError::queueCreate(std::string message, const CColor& color) {
void CHyprError::queueCreate(std::string message, const CHyprColor& color) {
m_szQueued = message;
m_cQueued = color;
}
@@ -98,7 +98,7 @@ void CHyprError::createQueued() {
cairo_stroke(CAIRO);
// draw the text with a common font
const CColor textColor = CColor(0.9, 0.9, 0.9, 1.0);
const CHyprColor textColor = CHyprColor(0.9, 0.9, 0.9, 1.0);
cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a);
static auto fontFamily = CConfigValue<std::string>("misc:font_family");
@@ -160,7 +160,7 @@ void CHyprError::createQueued() {
m_bIsCreated = true;
m_szQueued = "";
m_cQueued = CColor();
m_cQueued = CHyprColor();
g_pHyprRenderer->damageMonitor(PMONITOR);

View File

@@ -11,7 +11,7 @@ class CHyprError {
CHyprError();
~CHyprError();
void queueCreate(std::string message, const CColor& color);
void queueCreate(std::string message, const CHyprColor& color);
void draw();
void destroy();
@@ -21,7 +21,7 @@ class CHyprError {
private:
void createQueued();
std::string m_szQueued = "";
CColor m_cQueued;
CHyprColor m_cQueued;
bool m_bQueuedDestroy = false;
bool m_bIsCreated = false;
SP<CTexture> m_pTexture;

View File

@@ -9,11 +9,11 @@
#include <getopt.h>
#include <libinput.h>
#include <linux/input-event-codes.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <sys/wait.h>
#include <time.h>
#include <ctime>
#include <unistd.h>
#include <wayland-server-core.h>

View File

@@ -1,10 +1,10 @@
#include "initHelpers.hpp"
bool Init::isSudo() {
bool NInit::isSudo() {
return getuid() != geteuid() || !geteuid();
}
void Init::gainRealTime() {
void NInit::gainRealTime() {
const int minPrio = sched_get_priority_min(SCHED_RR);
int old_policy;
struct sched_param param;
@@ -21,7 +21,7 @@ void Init::gainRealTime() {
return;
}
pthread_atfork(NULL, NULL, []() {
pthread_atfork(nullptr, nullptr, []() {
const struct sched_param param = {.sched_priority = 0};
if (pthread_setschedparam(pthread_self(), SCHED_OTHER, &param))
Debug::log(WARN, "Failed to reset process scheduling strategy");

View File

@@ -2,7 +2,7 @@
#include "../defines.hpp"
namespace Init {
namespace NInit {
bool isSudo();
void gainRealTime();
};

View File

@@ -12,9 +12,9 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
if (*PPRESERVESPLIT == 0 && *PSMARTSPLIT == 0)
splitTop = box.h * *PFLMULT > box.w;
if (verticalOverride == true)
if (verticalOverride)
splitTop = true;
else if (horizontalOverride == true)
else if (horizontalOverride)
splitTop = false;
const auto SPLITSIDE = !splitTop;
@@ -38,13 +38,12 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
}
}
void SDwindleNodeData::getAllChildrenRecursive(std::deque<SDwindleNodeData*>* pDeque) {
void SDwindleNodeData::getAllChildrenRecursive(std::vector<SDwindleNodeData*>* pVec) {
if (children[0]) {
children[0]->getAllChildrenRecursive(pDeque);
children[1]->getAllChildrenRecursive(pDeque);
} else {
pDeque->push_back(this);
}
children[0]->getAllChildrenRecursive(pVec);
children[1]->getAllChildrenRecursive(pVec);
} else
pVec->push_back(this);
}
int CHyprDwindleLayout::getNodesOnWorkspace(const WORKSPACEID& id) {
@@ -231,7 +230,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
if (pWindow->m_bIsFloating)
return;
m_lDwindleNodesData.push_back(SDwindleNodeData());
m_lDwindleNodesData.emplace_back();
const auto PNODE = &m_lDwindleNodesData.back();
const auto PMONITOR = pWindow->m_pMonitor.lock();
@@ -283,7 +282,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
// first, check if OPENINGON isn't too big.
const auto PREDSIZEMAX = OPENINGON ? Vector2D(OPENINGON->box.w, OPENINGON->box.h) : PMONITOR->vecSize;
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) {
if (const auto MAXSIZE = pWindow->requestedMaxSize(); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
m_lDwindleNodesData.remove(*PNODE);
@@ -312,7 +311,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir
// get the node under our cursor
m_lDwindleNodesData.push_back(SDwindleNodeData());
m_lDwindleNodesData.emplace_back();
const auto NEWPARENT = &m_lDwindleNodesData.back();
// make the parent have the OPENINGON's stats
@@ -514,7 +513,7 @@ void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) {
if (pWorkspace->m_bHasFullscreenWindow) {
// massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID);
const auto PFULLWINDOW = pWorkspace->getFullscreenWindow();
if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) {
PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
@@ -805,14 +804,13 @@ void CHyprDwindleLayout::recalculateWindow(PHLWINDOW pWindow) {
PNODE->recalcSizePosRecursive();
}
void addToDequeRecursive(std::deque<SDwindleNodeData*>* pDeque, std::deque<SDwindleNodeData*>* pParents, SDwindleNodeData* node) {
static void addToVectorRecursive(std::vector<SDwindleNodeData*>* pVec, std::vector<SDwindleNodeData*>* pParents, SDwindleNodeData* node) {
if (node->isNode) {
pParents->push_back(node);
addToDequeRecursive(pDeque, pParents, node->children[0]);
addToDequeRecursive(pDeque, pParents, node->children[1]);
} else {
pDeque->emplace_back(node);
}
pParents->emplace_back(node);
addToVectorRecursive(pVec, pParents, node->children[0]);
addToVectorRecursive(pVec, pParents, node->children[1]);
} else
pVec->emplace_back(node);
}
SWindowRenderLayoutHints CHyprDwindleLayout::requestRenderHints(PHLWINDOW pWindow) {
@@ -1054,7 +1052,7 @@ void CHyprDwindleLayout::moveToRoot(PHLWINDOW pWindow, bool stable) {
std::swap(pRoot->children[0], pRoot->children[1]);
// if the workspace is visible, recalculate layout
if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace))
if (pWindow->m_pWorkspace && pWindow->m_pWorkspace->isVisible())
pRoot->recalcSizePosRecursive();
}
@@ -1094,7 +1092,7 @@ Vector2D CHyprDwindleLayout::predictSizeForNewWindowTiled() {
PHLWINDOW candidate = g_pCompositor->m_pLastWindow.lock();
if (!candidate)
candidate = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID);
candidate = g_pCompositor->m_pLastMonitor->activeWorkspace->getFirstWindow();
// create a fake node
SDwindleNodeData node;

View File

@@ -4,7 +4,7 @@
#include "../desktop/DesktopTypes.hpp"
#include <list>
#include <deque>
#include <vector>
#include <array>
#include <optional>
#include <format>
@@ -39,7 +39,7 @@ struct SDwindleNodeData {
}
void recalcSizePosRecursive(bool force = false, bool horizontalOverride = false, bool verticalOverride = false);
void getAllChildrenRecursive(std::deque<SDwindleNodeData*>*);
void getAllChildrenRecursive(std::vector<SDwindleNodeData*>*);
CHyprDwindleLayout* layout = nullptr;
};

View File

@@ -20,9 +20,6 @@ void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize;
if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows
pWindow->applyGroupRules();
bool autoGrouped = IHyprLayout::onWindowCreatedAutoGroup(pWindow);
if (autoGrouped)
return;
@@ -31,6 +28,9 @@ void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) {
onWindowCreatedFloating(pWindow);
else
onWindowCreatedTiling(pWindow, direction);
if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows
pWindow->applyGroupRules();
}
void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) {
@@ -81,7 +81,7 @@ void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) {
}
void IHyprLayout::onWindowRemovedFloating(PHLWINDOW pWindow) {
return; // no-op
; // no-op
}
void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) {
@@ -187,7 +187,7 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) {
static auto PAUTOGROUP = CConfigValue<Hyprlang::INT>("group:auto_group");
const PHLWINDOW OPENINGON = g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ?
g_pCompositor->m_pLastWindow.lock() :
g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID());
(pWindow->m_pWorkspace ? pWindow->m_pWorkspace->getFirstWindow() : nullptr);
const bool FLOATEDINTOTILED = pWindow->m_bIsFloating && !OPENINGON->m_bIsFloating;
const bool SWALLOWING = pWindow->m_pSwallowed || pWindow->m_bGroupSwallowed;
@@ -455,7 +455,7 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA
// corner snapping
const double BORDERDIFF = OTHERBORDERSIZE - DRAGGINGBORDERSIZE;
if (sourceX.start == SURFBX.end || SURFBX.start == sourceX.end) {
if (snaps & (SNAP_LEFT | SNAP_RIGHT)) {
const SRange SURFY = {SURF.y - BORDERDIFF, SURF.y + SURF.h + BORDERDIFF};
if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceY.start, SURFY.start, GAPSIZE)) {
SNAP(sourceY.start, sourceY.end, SURFY.start);
@@ -465,7 +465,7 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA
snaps |= SNAP_DOWN;
}
}
if (sourceY.start == SURFBY.end || SURFBY.start == sourceY.end) {
if (snaps & (SNAP_UP | SNAP_DOWN)) {
const SRange SURFX = {SURF.x - BORDERDIFF, SURF.x + SURF.w + BORDERDIFF};
if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceX.start, SURFX.start, GAPSIZE)) {
SNAP(sourceX.start, sourceX.end, SURFX.start);
@@ -480,26 +480,35 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA
if (*SNAPMONITORGAP) {
const double GAPSIZE = *SNAPMONITORGAP;
const double BORDERSIZE = OVERLAP ? 0 : DRAGGINGBORDERSIZE;
const double BORDERDIFF = DRAGGINGBORDERSIZE - BORDERSIZE;
const double BORDERDIFF = OVERLAP ? DRAGGINGBORDERSIZE : 0;
const auto MON = DRAGGINGWINDOW->m_pMonitor.lock();
SRange monX = {MON->vecPosition.x + BORDERSIZE, MON->vecSize.x - BORDERSIZE};
SRange monY = {MON->vecPosition.y + BORDERSIZE, MON->vecSize.y - BORDERSIZE};
SRange monX = {MON->vecPosition.x + MON->vecReservedTopLeft.x + DRAGGINGBORDERSIZE,
MON->vecPosition.x + MON->vecSize.x - MON->vecReservedBottomRight.x - DRAGGINGBORDERSIZE};
SRange monY = {MON->vecPosition.y + MON->vecReservedTopLeft.y + DRAGGINGBORDERSIZE,
MON->vecPosition.y + MON->vecSize.y - MON->vecReservedBottomRight.y - DRAGGINGBORDERSIZE};
if (canSnap(sourceX.start, monX.start, GAPSIZE) || canSnap(sourceX.start, (monX.start += MON->vecReservedTopLeft.x + BORDERDIFF), GAPSIZE)) {
if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) &&
((MON->vecReservedTopLeft.x > 0 && canSnap(sourceX.start, monX.start, GAPSIZE)) ||
canSnap(sourceX.start, (monX.start -= MON->vecReservedTopLeft.x + BORDERDIFF), GAPSIZE))) {
SNAP(sourceX.start, sourceX.end, monX.start);
snaps |= SNAP_LEFT;
}
if (canSnap(sourceX.end, monX.end, GAPSIZE) || canSnap(sourceX.end, (monX.end -= MON->vecReservedBottomRight.x + BORDERDIFF), GAPSIZE)) {
if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) &&
((MON->vecReservedBottomRight.x > 0 && canSnap(sourceX.end, monX.end, GAPSIZE)) ||
canSnap(sourceX.end, (monX.end += MON->vecReservedBottomRight.x + BORDERDIFF), GAPSIZE))) {
SNAP(sourceX.end, sourceX.start, monX.end);
snaps |= SNAP_RIGHT;
}
if (canSnap(sourceY.start, monY.start, GAPSIZE) || canSnap(sourceY.start, (monY.start += MON->vecReservedTopLeft.y + BORDERDIFF), GAPSIZE)) {
if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) &&
((MON->vecReservedTopLeft.y > 0 && canSnap(sourceY.start, monY.start, GAPSIZE)) ||
canSnap(sourceY.start, (monY.start -= MON->vecReservedTopLeft.y + BORDERDIFF), GAPSIZE))) {
SNAP(sourceY.start, sourceY.end, monY.start);
snaps |= SNAP_UP;
}
if (canSnap(sourceY.end, monY.end, GAPSIZE) || canSnap(sourceY.end, (monY.end -= MON->vecReservedBottomRight.y + BORDERDIFF), GAPSIZE)) {
if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) &&
((MON->vecReservedBottomRight.y > 0 && canSnap(sourceY.end, monY.end, GAPSIZE)) ||
canSnap(sourceY.end, (monY.end += MON->vecReservedBottomRight.y + BORDERDIFF), GAPSIZE))) {
SNAP(sourceY.end, sourceY.start, monY.end);
snaps |= SNAP_DOWN;
}
@@ -597,12 +606,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
} else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) {
if (DRAGGINGWINDOW->m_bIsFloating) {
Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sWindowData.minSize.valueOr(Vector2D(20, 20)));
Vector2D MINSIZE = DRAGGINGWINDOW->requestedMinSize().clamp(DRAGGINGWINDOW->m_sWindowData.minSize.valueOr(Vector2D(20, 20)));
Vector2D MAXSIZE;
if (DRAGGINGWINDOW->m_sWindowData.maxSize.hasValue())
MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, DRAGGINGWINDOW->m_sWindowData.maxSize.value());
MAXSIZE = DRAGGINGWINDOW->requestedMaxSize().clamp({}, DRAGGINGWINDOW->m_sWindowData.maxSize.value());
else
MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max()));
MAXSIZE = DRAGGINGWINDOW->requestedMaxSize().clamp({}, Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max()));
Vector2D newSize = m_vBeginDragSizeXY;
Vector2D newPos = m_vBeginDragPositionXY;
@@ -714,7 +723,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) {
const auto PWORKSPACE = PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow)
g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), FSMODE_NONE);
g_pCompositor->setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE);
// save real pos cuz the func applies the default 5,5 mid
const auto PSAVEDPOS = pWindow->m_vRealPosition.goal();
@@ -803,7 +812,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) {
// first of all, if this is a fullscreen workspace,
if (PWORKSPACE->m_bHasFullscreenWindow)
return g_pCompositor->getFullscreenWindowOnWorkspace(pWindow->workspaceID());
return PWORKSPACE->getFullscreenWindow();
if (pWindow->m_bIsFloating) {
@@ -842,10 +851,10 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) {
auto pWindowCandidate = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!pWindowCandidate)
pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->workspaceID());
pWindowCandidate = PWORKSPACE->getTopLeftWindow();
if (!pWindowCandidate)
pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID());
pWindowCandidate = PWORKSPACE->getFirstWindow();
if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus ||
pWindowCandidate->isX11OverrideRedirect() || pWindowCandidate->m_pMonitor != g_pCompositor->m_pLastMonitor)
@@ -878,25 +887,26 @@ Vector2D IHyprLayout::predictSizeForNewWindowFloating(PHLWINDOW pWindow) { // ge
Vector2D sizeOverride = {};
if (g_pCompositor->m_pLastMonitor) {
for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) {
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(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
if (r->ruleType != CWindowRule::RULE_SIZE)
continue;
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow);
try {
const auto VALUE = r->szRule.substr(r->szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.x) :
stringToPercentage(SIZEXSTR, g_pCompositor->m_pLastMonitor->vecSize.x);
const auto MAXSIZE = pWindow->requestedMaxSize();
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.y) :
stringToPercentage(SIZEYSTR, g_pCompositor->m_pLastMonitor->vecSize.y);
const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.x) :
stringToPercentage(SIZEXSTR, g_pCompositor->m_pLastMonitor->vecSize.x);
sizeOverride = {SIZEX, SIZEY};
const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.y) :
stringToPercentage(SIZEYSTR, g_pCompositor->m_pLastMonitor->vecSize.y);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
break;
}
sizeOverride = {SIZEX, SIZEY};
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r->szRule, r->szValue); }
break;
}
}
@@ -908,10 +918,11 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) {
if (!shouldBeFloated) {
for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) {
if (r.szRule.starts_with("float")) {
shouldBeFloated = true;
break;
}
if (r->ruleType != CWindowRule::RULE_FLOAT)
continue;
shouldBeFloated = true;
break;
}
}
@@ -930,4 +941,4 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) {
return sizePredicted;
}
IHyprLayout::~IHyprLayout() {}
IHyprLayout::~IHyprLayout() = default;

View File

@@ -17,7 +17,7 @@ struct SLayoutMessageHeader {
enum eFullscreenMode : int8_t;
enum eRectCorner {
enum eRectCorner : uint8_t {
CORNER_NONE = 0,
CORNER_TOPLEFT = (1 << 0),
CORNER_TOPRIGHT = (1 << 1),
@@ -25,7 +25,7 @@ enum eRectCorner {
CORNER_BOTTOMLEFT = (1 << 3),
};
enum eSnapEdge {
enum eSnapEdge : uint8_t {
SNAP_INVALID = 0,
SNAP_UP = (1 << 0),
SNAP_DOWN = (1 << 1),
@@ -33,7 +33,7 @@ enum eSnapEdge {
SNAP_RIGHT = (1 << 3),
};
enum eDirection {
enum eDirection : int8_t {
DIRECTION_DEFAULT = -1,
DIRECTION_UP = 0,
DIRECTION_RIGHT,

View File

@@ -200,7 +200,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
PNODE->percMaster = lastSplitPercent;
// first, check if it isn't too big.
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PMONITOR->vecSize.x * lastSplitPercent || MAXSIZE.y < PMONITOR->vecSize.y) {
if (const auto MAXSIZE = pWindow->requestedMaxSize(); MAXSIZE.x < PMONITOR->vecSize.x * lastSplitPercent || MAXSIZE.y < PMONITOR->vecSize.y) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
m_lMasterNodesData.remove(*PNODE);
@@ -212,7 +212,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
PNODE->percMaster = lastSplitPercent;
// first, check if it isn't too big.
if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow);
if (const auto MAXSIZE = pWindow->requestedMaxSize();
MAXSIZE.x < PMONITOR->vecSize.x * (1 - lastSplitPercent) || MAXSIZE.y < PMONITOR->vecSize.y * (1.f / (WINDOWSONWORKSPACE - 1))) {
// we can't continue. make it floating.
pWindow->m_bIsFloating = true;
@@ -267,7 +267,7 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
// the screen half bare, and make it difficult to select remaining window
if (getNodesOnWorkspace(WORKSPACEID) == 1) {
for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID == WORKSPACEID && nd.isMaster == false) {
if (nd.workspaceID == WORKSPACEID && !nd.isMaster) {
nd.isMaster = true;
break;
}
@@ -298,7 +298,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
if (pWorkspace->m_bHasFullscreenWindow) {
// massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID);
const auto PFULLWINDOW = pWorkspace->getFullscreenWindow();
if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) {
PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
@@ -328,6 +328,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
eOrientation orientation = getDynamicOrientation(pWorkspace);
bool centerMasterWindow = false;
static auto ALWAYSCENTER = CConfigValue<Hyprlang::INT>("master:always_center_master");
static auto PIGNORERESERVED = CConfigValue<Hyprlang::INT>("master:center_ignores_reserved");
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing");
const auto MASTERS = getMastersOnWorkspace(pWorkspace->m_iID);
@@ -402,7 +403,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
nextX += WIDTH;
}
} else { // orientation left, right or center
float WIDTH = WSSIZE.x;
float WIDTH = *PIGNORERESERVED && centerMasterWindow ? PMONITOR->vecSize.x : WSSIZE.x;
float heightLeft = WSSIZE.y;
int mastersLeft = MASTERS;
float nextX = 0;
@@ -414,7 +415,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
if (orientation == ORIENTATION_RIGHT) {
nextX = WSSIZE.x - WIDTH;
} else if (centerMasterWindow) {
nextX = (WSSIZE.x - WIDTH) / 2;
nextX = ((*PIGNORERESERVED && centerMasterWindow ? PMONITOR->vecSize.x : WSSIZE.x) - WIDTH) / 2;
}
for (auto& nd : m_lMasterNodesData) {
@@ -431,7 +432,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
}
nd.size = Vector2D(WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
nd.position = (*PIGNORERESERVED && centerMasterWindow ? PMONITOR->vecPosition : WSPOS) + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);
mastersLeft--;
@@ -506,7 +507,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
nextY += HEIGHT;
}
} else { // slaves for centered master window(s)
const float WIDTH = (WSSIZE.x - PMASTERNODE->size.x) / 2.0;
const float WIDTH = ((*PIGNORERESERVED ? PMONITOR->vecSize.x : WSSIZE.x) - PMASTERNODE->size.x) / 2.0;
float heightLeft = 0;
float heightLeftL = WSSIZE.y;
float heightLeftR = WSSIZE.y;
@@ -543,7 +544,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
continue;
if (onRight) {
nextX = WIDTH + PMASTERNODE->size.x;
nextX = WIDTH + PMASTERNODE->size.x - (*PIGNORERESERVED ? PMONITOR->vecReservedTopLeft.x : 0);
nextY = nextYR;
heightLeft = heightLeftR;
slavesLeft = slavesLeftR;
@@ -568,7 +569,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
}
}
nd.size = Vector2D(WIDTH, HEIGHT);
nd.size = Vector2D(*PIGNORERESERVED ? (WIDTH - (onRight ? PMONITOR->vecReservedBottomRight.x : PMONITOR->vecReservedTopLeft.x)) : WIDTH, HEIGHT);
nd.position = WSPOS + Vector2D(nextX, nextY);
applyNodeDataToWindow(&nd);

View File

@@ -5,7 +5,7 @@
#include "../config/ConfigManager.hpp"
#include <vector>
#include <list>
#include <deque>
#include <vector>
#include <any>
enum eFullscreenMode : int8_t;

View File

@@ -16,8 +16,6 @@
#define ISDEBUG false
#endif
#include "version.h"
#define SPECIAL_WORKSPACE_START (-99)
#define PI 3.14159265358979

View File

@@ -54,11 +54,11 @@ int main(int argc, char** argv) {
std::vector<std::string> args{argv + 1, argv + argc};
for (auto it = args.begin(); it != args.end(); it++) {
if (it->compare("--i-am-really-stupid") == 0 && !ignoreSudo) {
if (*it == "--i-am-really-stupid" && !ignoreSudo) {
std::println("[ WARNING ] Running Hyprland with superuser privileges might damage your system");
ignoreSudo = true;
} else if (it->compare("--socket") == 0) {
} else if (*it == "--socket") {
if (std::next(it) == args.end()) {
help();
@@ -67,7 +67,7 @@ int main(int argc, char** argv) {
socketName = *std::next(it);
it++;
} else if (it->compare("--wayland-fd") == 0) {
} else if (*it == "--wayland-fd") {
if (std::next(it) == args.end()) {
help();
@@ -75,7 +75,7 @@ int main(int argc, char** argv) {
}
try {
socketFd = std::stoi(std::next(it)->c_str());
socketFd = std::stoi(*std::next(it));
// check if socketFd is a valid file descriptor
if (fcntl(socketFd, F_GETFD) == -1)
@@ -88,13 +88,13 @@ int main(int argc, char** argv) {
}
it++;
} else if (it->compare("-c") == 0 || it->compare("--config") == 0) {
} else if (*it == "-c" || *it == "--config") {
if (std::next(it) == args.end()) {
help();
return 1;
}
configPath = std::next(it)->c_str();
configPath = *std::next(it);
try {
configPath = std::filesystem::canonical(configPath);
@@ -114,31 +114,31 @@ int main(int argc, char** argv) {
it++;
continue;
} else if (it->compare("-h") == 0 || it->compare("--help") == 0) {
} else if (*it == "-h" || *it == "--help") {
help();
return 0;
} else if (it->compare("-v") == 0 || it->compare("--version") == 0) {
} else if (*it == "-v" || *it == "--version") {
std::println("{}", versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""));
return 0;
} else if (it->compare("--systeminfo") == 0) {
} else if (*it == "--systeminfo") {
std::println("{}", systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""));
return 0;
} else {
std::println(stderr, "[ ERROR ] Unknown option '{}' !", it->c_str());
std::println(stderr, "[ ERROR ] Unknown option '{}' !", *it);
help();
return 1;
}
}
if (!ignoreSudo && Init::isSudo()) {
if (!ignoreSudo && NInit::isSudo()) {
std::println(stderr,
"[ ERROR ] Hyprland was launched with superuser privileges, but the privileges check is not omitted.\n"
" Hint: Use the --i-am-really-stupid flag to omit that check.");
return 1;
} else if (ignoreSudo && Init::isSudo()) {
} else if (ignoreSudo && NInit::isSudo()) {
std::println("Superuser privileges check is omitted. I hope you know what you're doing.");
}
@@ -165,7 +165,7 @@ int main(int argc, char** argv) {
g_pCompositor->initServer(socketName, socketFd);
if (!envEnabled("HYPRLAND_NO_RT"))
Init::gainRealTime();
NInit::gainRealTime();
Debug::log(LOG, "Hyprland init finished.");

View File

@@ -8,6 +8,8 @@
#include "eventLoop/EventLoopManager.hpp"
#include "../helpers/varlist/VarList.hpp"
#include <hyprgraphics/color/Color.hpp>
int wlTick(SP<CEventLoopTimer> self, void* data) {
if (g_pAnimationManager)
g_pAnimationManager->onTicked();
@@ -149,14 +151,14 @@ void CAnimationManager::tick() {
animationsDisabled = animationsDisabled || PLAYER->noAnimations;
}
const bool VISIBLE = PWINDOW && PWINDOW->m_pWorkspace ? g_pCompositor->isWorkspaceVisible(PWINDOW->m_pWorkspace) : true;
const bool VISIBLE = PWINDOW && PWINDOW->m_pWorkspace ? PWINDOW->m_pWorkspace->isVisible() : true;
// beziers are with a switch unforto
// TODO: maybe do something cleaner
auto updateVariable = [&]<Animable T>(CAnimatedVariable<T>& av) {
static const auto updateVariable = [this]<Animable T>(CAnimatedVariable<T>& av, const float SPENT, const CBezierCurve& DEFAULTBEZIER, const bool DISABLED) {
// for disabled anims just warp
if (av.m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
if (av.m_pConfig->pValues->internalEnabled == 0 || DISABLED) {
av.warp(false);
return;
}
@@ -166,29 +168,66 @@ void CAnimationManager::tick() {
return;
}
const auto DELTA = av.m_Goal - av.m_Begun;
const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier);
const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER.getYForPoint(SPENT);
const auto DELTA = av.m_Goal - av.m_Begun;
if (BEZIER != m_mBezierCurves.end())
av.m_Value = av.m_Begun + DELTA * BEZIER->second.getYForPoint(SPENT);
av.m_Value = av.m_Begun + DELTA * POINTY;
else
av.m_Value = av.m_Begun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT);
av.m_Value = av.m_Begun + DELTA * POINTY;
};
static const auto updateColorVariable = [this](CAnimatedVariable<CHyprColor>& av, const float SPENT, const CBezierCurve& DEFAULTBEZIER, const bool DISABLED) {
// for disabled anims just warp
if (av.m_pConfig->pValues->internalEnabled == 0 || DISABLED) {
av.warp(false);
return;
}
if (SPENT >= 1.f || av.m_Begun == av.m_Goal) {
av.warp(false);
return;
}
const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier);
const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER.getYForPoint(SPENT);
// convert both to OkLab, then lerp that, and convert back.
// This is not as fast as just lerping rgb, but it's WAY more precise...
// Use the CHyprColor cache for OkLab
const auto& L1 = av.m_Begun.asOkLab();
const auto& L2 = av.m_Goal.asOkLab();
static const auto lerp = [](const float one, const float two, const float progress) -> float { return one + (two - one) * progress; };
const Hyprgraphics::CColor lerped = Hyprgraphics::CColor::SOkLab{
.l = lerp(L1.l, L2.l, POINTY),
.a = lerp(L1.a, L2.a, POINTY),
.b = lerp(L1.b, L2.b, POINTY),
};
av.m_Value = {lerped, lerp(av.m_Begun.a, av.m_Goal.a, POINTY)};
return;
};
switch (av->m_Type) {
case AVARTYPE_FLOAT: {
auto typedAv = static_cast<CAnimatedVariable<float>*>(av);
updateVariable(*typedAv);
auto typedAv = dynamic_cast<CAnimatedVariable<float>*>(av);
updateVariable(*typedAv, SPENT, DEFAULTBEZIER->second, animationsDisabled);
break;
}
case AVARTYPE_VECTOR: {
auto typedAv = static_cast<CAnimatedVariable<Vector2D>*>(av);
updateVariable(*typedAv);
auto typedAv = dynamic_cast<CAnimatedVariable<Vector2D>*>(av);
updateVariable(*typedAv, SPENT, DEFAULTBEZIER->second, animationsDisabled);
break;
}
case AVARTYPE_COLOR: {
auto typedAv = static_cast<CAnimatedVariable<CColor>*>(av);
updateVariable(*typedAv);
auto typedAv = dynamic_cast<CAnimatedVariable<CHyprColor>*>(av);
updateColorVariable(*typedAv, SPENT, DEFAULTBEZIER->second, animationsDisabled);
break;
}
default: UNREACHABLE();
@@ -262,7 +301,7 @@ void CAnimationManager::tick() {
g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION);
}
// do it here, because if this alters the animation vars deque we would be in trouble above.
// do it here, because if this alters the animation vars vec we would be in trouble above.
for (auto const& ave : animationEndedVars) {
ave->onAnimationEnd();
}
@@ -272,7 +311,7 @@ bool CAnimationManager::deltaSmallToFlip(const Vector2D& a, const Vector2D& b) {
return std::abs(a.x - b.x) < 0.5f && std::abs(a.y - b.y) < 0.5f;
}
bool CAnimationManager::deltaSmallToFlip(const CColor& a, const CColor& b) {
bool CAnimationManager::deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b) {
return std::abs(a.r - b.r) < 0.5f && std::abs(a.g - b.g) < 0.5f && std::abs(a.b - b.b) < 0.5f && std::abs(a.a - b.a) < 0.5f;
}
@@ -288,7 +327,7 @@ bool CAnimationManager::deltazero(const float& a, const float& b) {
return a == b;
}
bool CAnimationManager::deltazero(const CColor& a, const CColor& b) {
bool CAnimationManager::deltazero(const CHyprColor& a, const CHyprColor& b) {
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
@@ -456,7 +495,7 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config,
else if (style.starts_with("popin")) {
// try parsing
float minPerc = 0.f;
if (style.find("%") != std::string::npos) {
if (style.find('%') != std::string::npos) {
try {
auto percstr = style.substr(style.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
@@ -477,7 +516,7 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config,
else if (style.starts_with("slidefade")) {
// try parsing
float movePerc = 0.f;
if (style.find("%") != std::string::npos) {
if (style.find('%') != std::string::npos) {
try {
auto percstr = style.substr(style.find_last_of(' ') + 1);
movePerc = std::stoi(percstr.substr(0, percstr.length() - 1));
@@ -502,7 +541,7 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config,
else if (style.starts_with("popin")) {
// try parsing
float minPerc = 0.f;
if (style.find("%") != std::string::npos) {
if (style.find('%') != std::string::npos) {
try {
auto percstr = style.substr(style.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));

View File

@@ -39,10 +39,10 @@ class CAnimationManager {
private:
bool deltaSmallToFlip(const Vector2D& a, const Vector2D& b);
bool deltaSmallToFlip(const CColor& a, const CColor& b);
bool deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b);
bool deltaSmallToFlip(const float& a, const float& b);
bool deltazero(const Vector2D& a, const Vector2D& b);
bool deltazero(const CColor& a, const CColor& b);
bool deltazero(const CHyprColor& a, const CHyprColor& b);
bool deltazero(const float& a, const float& b);
std::unordered_map<std::string, CBezierCurve> m_mBezierCurves;

View File

@@ -17,16 +17,12 @@ static void hcLogger(enum eHyprcursorLogLevel level, char* message) {
Debug::log(NONE, "[hc] {}", message);
}
CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
surface = surf;
size = size_;
stride = cairo_image_surface_get_stride(surf);
CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_), surface(surf), stride(cairo_image_surface_get_stride(surf)) {
size = size_;
}
CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
pixelData = pixelData_;
size = size_;
stride = 4 * size_.x;
CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_), pixelData(pixelData_), stride(4 * size_.x) {
size = size_;
}
Aquamarine::eBufferCapability CCursorBuffer::caps() {

View File

@@ -10,8 +10,7 @@
#include <unistd.h>
#include <cstring>
CEventManager::CEventManager() {
m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) {
if (m_iSocketFD < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work.");
return;
@@ -117,7 +116,7 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) {
if (write(CLIENTIT->fd, event->c_str(), event->length()) < 0)
break;
CLIENTIT->events.pop_front();
CLIENTIT->events.erase(CLIENTIT->events.begin());
}
// stop polling when we sent all events

View File

@@ -1,5 +1,5 @@
#pragma once
#include <deque>
#include <vector>
#include <vector>
#include "../defines.hpp"
@@ -27,9 +27,9 @@ class CEventManager {
int onClientEvent(int fd, uint32_t mask);
struct SClient {
int fd = -1;
std::deque<SP<std::string>> events;
wl_event_source* eventSource = nullptr;
int fd = -1;
std::vector<SP<std::string>> events;
wl_event_source* eventSource = nullptr;
};
std::vector<SClient>::iterator findClientByFD(int fd);

View File

@@ -5,7 +5,6 @@
#include "../protocols/ShortcutsInhibit.hpp"
#include "../protocols/GlobalShortcuts.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../devices/IKeyboard.hpp"
#include "KeybindManager.hpp"
#include "PointerManager.hpp"
#include "Compositor.hpp"
@@ -130,9 +129,44 @@ CKeybindManager::CKeybindManager() {
m_tScrollTimer.reset();
m_pLongPressTimer = makeShared<CEventLoopTimer>(
std::nullopt,
[this](SP<CEventLoopTimer> self, void* data) {
if (!m_pLastLongPressKeybind || g_pSeatManager->keyboard.expired())
return;
const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(m_pLastLongPressKeybind->handler);
Debug::log(LOG, "Long press timeout passed, calling dispatcher.");
DISPATCHER->second(m_pLastLongPressKeybind->arg);
},
nullptr);
m_pRepeatKeyTimer = makeShared<CEventLoopTimer>(
std::nullopt,
[this](SP<CEventLoopTimer> self, void* data) {
if (m_vActiveKeybinds.size() == 0 || g_pSeatManager->keyboard.expired())
return;
for (const auto& k : m_vActiveKeybinds) {
const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(k->handler);
Debug::log(LOG, "Keybind repeat triggered, calling dispatcher.");
DISPATCHER->second(k->arg);
}
const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock();
self->updateTimeout(std::chrono::milliseconds(1000 / PACTIVEKEEB->repeatRate));
},
nullptr);
g_pEventLoopManager->addTimer(m_pLongPressTimer);
g_pEventLoopManager->addTimer(m_pRepeatKeyTimer);
static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) {
// clear cuz realloc'd
m_pActiveKeybind = nullptr;
m_vActiveKeybinds.clear();
m_pLastLongPressKeybind.reset();
m_vPressedSpecialBinds.clear();
});
}
@@ -140,25 +174,28 @@ CKeybindManager::CKeybindManager() {
CKeybindManager::~CKeybindManager() {
if (m_pXKBTranslationState)
xkb_state_unref(m_pXKBTranslationState);
if (m_pLongPressTimer && g_pEventLoopManager) {
g_pEventLoopManager->removeTimer(m_pLongPressTimer);
m_pLongPressTimer.reset();
}
if (m_pRepeatKeyTimer && g_pEventLoopManager) {
g_pEventLoopManager->removeTimer(m_pRepeatKeyTimer);
m_pRepeatKeyTimer.reset();
}
}
void CKeybindManager::addKeybind(SKeybind kb) {
m_lKeybinds.push_back(kb);
m_vKeybinds.emplace_back(makeShared<SKeybind>(kb));
m_pActiveKeybind = nullptr;
m_vActiveKeybinds.clear();
m_pLastLongPressKeybind.reset();
}
void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) {
for (auto it = m_lKeybinds.begin(); it != m_lKeybinds.end(); ++it) {
if (it->modmask == mod && it->key == key.key && it->keycode == key.keycode && it->catchAll == key.catchAll) {
it = m_lKeybinds.erase(it);
std::erase_if(m_vKeybinds, [&mod, &key](const auto& el) { return el->modmask == mod && el->key == key.key && el->keycode == key.keycode && el->catchAll == key.catchAll; });
if (it == m_lKeybinds.end())
break;
}
}
m_pActiveKeybind = nullptr;
m_vActiveKeybinds.clear();
m_pLastLongPressKeybind.reset();
}
uint32_t CKeybindManager::stringToModMask(std::string mods) {
@@ -226,7 +263,7 @@ void CKeybindManager::updateXKBTranslationState() {
xkb_rule_names rules = {.rules = RULES.c_str(), .model = MODEL.c_str(), .layout = LAYOUT.c_str(), .variant = VARIANT.c_str(), .options = OPTIONS.c_str()};
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
FILE* const KEYMAPFILE = FILEPATH == "" ? NULL : fopen(absolutePath(FILEPATH, g_pConfigManager->configCurrentPath).c_str(), "r");
FILE* const KEYMAPFILE = FILEPATH == "" ? nullptr : fopen(absolutePath(FILEPATH, g_pConfigManager->configCurrentPath).c_str(), "r");
auto PKEYMAP = KEYMAPFILE ? xkb_keymap_new_from_file(PCONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS) :
xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
@@ -236,7 +273,7 @@ void CKeybindManager::updateXKBTranslationState() {
if (!PKEYMAP) {
g_pHyprError->queueCreate("[Runtime Error] Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS +
", layout: " + LAYOUT + " )",
CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
Debug::log(ERR, "[XKBTranslationState] Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant,
rules.rules, rules.model, rules.options);
@@ -338,6 +375,10 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
if (!PWINDOWTOCHANGETO->m_bPinned)
g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE);
// warp the position + size animation, otherwise it looks weird.
PWINDOWTOCHANGETO->m_vRealPosition.warp();
PWINDOWTOCHANGETO->m_vRealSize.warp();
} else {
updateRelativeCursorCoords();
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
@@ -366,7 +407,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
}
if (!m_pXKBTranslationState) {
Debug::log(ERR, "BUG THIS: m_pXKBTranslationState NULL!");
Debug::log(ERR, "BUG THIS: m_pXKBTranslationState nullptr!");
updateXKBTranslationState();
if (!m_pXKBTranslationState)
@@ -380,8 +421,10 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbSymState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE);
// handleInternalKeybinds returns true when the key should be suppressed,
// while this function returns true when the key event should be sent
if (handleInternalKeybinds(internalKeysym))
return true;
return false;
const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
@@ -399,11 +442,9 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
.submapAtPress = m_szCurrentSelectedSubmap,
};
if (m_pActiveKeybindEventSource) {
wl_event_source_remove(m_pActiveKeybindEventSource);
m_pActiveKeybindEventSource = nullptr;
m_pActiveKeybind = nullptr;
}
m_vActiveKeybinds.clear();
m_pLastLongPressKeybind.reset();
bool suppressEvent = false;
if (e.state == WL_KEYBOARD_KEY_STATE_PRESSED) {
@@ -453,11 +494,7 @@ bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) {
m_tScrollTimer.reset();
if (m_pActiveKeybindEventSource) {
wl_event_source_remove(m_pActiveKeybindEventSource);
m_pActiveKeybindEventSource = nullptr;
m_pActiveKeybind = nullptr;
}
m_vActiveKeybinds.clear();
bool found = false;
if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
@@ -496,11 +533,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) {
.modmaskAtPressTime = MODS,
};
if (m_pActiveKeybindEventSource) {
wl_event_source_remove(m_pActiveKeybindEventSource);
m_pActiveKeybindEventSource = nullptr;
m_pActiveKeybind = nullptr;
}
m_vActiveKeybinds.clear();
if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) {
m_dPressedKeys.push_back(KEY);
@@ -551,22 +584,6 @@ void CKeybindManager::onSwitchOffEvent(const std::string& switchName) {
handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:off:" + switchName}, true);
}
int repeatKeyHandler(void* data) {
SKeybind** ppActiveKeybind = (SKeybind**)data;
if (!*ppActiveKeybind || g_pSeatManager->keyboard.expired())
return 0;
const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find((*ppActiveKeybind)->handler);
Debug::log(LOG, "Keybind repeat triggered, calling dispatcher.");
DISPATCHER->second((*ppActiveKeybind)->arg);
wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->repeatRate);
return 0;
}
eMultiKeyCase CKeybindManager::mkKeysymSetMatches(const std::set<xkb_keysym_t> keybindKeysyms, const std::set<xkb_keysym_t> pressedKeysyms) {
// Returns whether two sets of keysyms are equal, partially equal, or not
// matching. (Partially matching means that pressed is a subset of bound)
@@ -588,11 +605,11 @@ eMultiKeyCase CKeybindManager::mkKeysymSetMatches(const std::set<xkb_keysym_t> k
return MK_NO_MATCH;
}
eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) {
if (mkKeysymSetMatches(keybind.sMkMods, m_sMkMods) != MK_FULL_MATCH)
eMultiKeyCase CKeybindManager::mkBindMatches(const SP<SKeybind> keybind) {
if (mkKeysymSetMatches(keybind->sMkMods, m_sMkMods) != MK_FULL_MATCH)
return MK_NO_MATCH;
return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys);
return mkKeysymSetMatches(keybind->sMkKeys, m_sMkKeys);
}
std::string CKeybindManager::getCurrentSubmap() {
@@ -616,35 +633,35 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
m_sMkKeys.erase(key.keysym);
}
for (auto& k : m_lKeybinds) {
const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse";
for (auto& k : m_vKeybinds) {
const bool SPECIALDISPATCHER = k->handler == "global" || k->handler == "pass" || k->handler == "sendshortcut" || k->handler == "mouse";
const bool SPECIALTRIGGERED =
std::find_if(m_vPressedSpecialBinds.begin(), m_vPressedSpecialBinds.end(), [&](const auto& other) { return other == &k; }) != m_vPressedSpecialBinds.end();
std::find_if(m_vPressedSpecialBinds.begin(), m_vPressedSpecialBinds.end(), [&](const auto& other) { return other == k; }) != m_vPressedSpecialBinds.end();
const bool IGNORECONDITIONS =
SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released.
if (!k.dontInhibit && !*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited())
if (!k->dontInhibit && !*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited())
continue;
if (!k.locked && g_pSessionLockManager->isSessionLocked())
if (!k->locked && g_pSessionLockManager->isSessionLocked())
continue;
if (!IGNORECONDITIONS && ((modmask != k.modmask && !k.ignoreMods) || k.submap != m_szCurrentSelectedSubmap || k.shadowed))
if (!IGNORECONDITIONS && ((modmask != k->modmask && !k->ignoreMods) || k->submap != m_szCurrentSelectedSubmap || k->shadowed))
continue;
if (k.multiKey) {
if (k->multiKey) {
switch (mkBindMatches(k)) {
case MK_NO_MATCH: continue;
case MK_PARTIAL_MATCH: found = true; continue;
case MK_FULL_MATCH: found = true;
}
} else if (!key.keyName.empty()) {
if (key.keyName != k.key)
if (key.keyName != k->key)
continue;
} else if (k.keycode != 0) {
if (key.keycode != k.keycode)
} else if (k->keycode != 0) {
if (key.keycode != k->keycode)
continue;
} else if (k.catchAll) {
} else if (k->catchAll) {
if (found || key.submapAtPress != m_szCurrentSelectedSubmap)
continue;
} else {
@@ -655,8 +672,8 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
// oMg such performance hit!!11!
// this little maneouver is gonna cost us 4µs
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_NO_FLAGS);
const auto KBKEYLOWER = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
const auto KBKEY = xkb_keysym_from_name(k->key.c_str(), XKB_KEYSYM_NO_FLAGS);
const auto KBKEYLOWER = xkb_keysym_from_name(k->key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
if (KBKEY == XKB_KEY_NoSymbol && KBKEYLOWER == XKB_KEY_NoSymbol) {
// Keysym failed to resolve from the key name of the currently iterated bind.
@@ -673,8 +690,8 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
continue;
}
if (pressed && k.release && !SPECIALDISPATCHER) {
if (k.nonConsuming)
if (pressed && k->release && !SPECIALDISPATCHER) {
if (k->nonConsuming)
continue;
found = true; // suppress the event
@@ -683,7 +700,7 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
if (!pressed) {
// Require mods to be matching when the key was first pressed.
if (key.modmaskAtPressTime != modmask && !k.ignoreMods) {
if (key.modmaskAtPressTime != modmask && !k->ignoreMods) {
// Handle properly `bindr` where a key is itself a bind mod for example:
// "bindr = SUPER, SUPER_L, exec, $launcher".
// This needs to be handled separately for the above case, because `key.modmaskAtPressTime` is set
@@ -692,8 +709,8 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
if (keycodeToModifier(key.keycode) == key.modmaskAtPressTime)
continue;
} else if (!k.release && !SPECIALDISPATCHER) {
if (k.nonConsuming)
} else if (!k->release && !SPECIALDISPATCHER) {
if (k->nonConsuming)
continue;
found = true; // suppress the event
@@ -701,16 +718,25 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
}
}
const auto DISPATCHER = m_mDispatchers.find(k.mouse ? "mouse" : k.handler);
if (k->longPress) {
const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock();
m_pLongPressTimer->updateTimeout(std::chrono::milliseconds(PACTIVEKEEB->repeatDelay));
m_pLastLongPressKeybind = k;
continue;
}
const auto DISPATCHER = m_mDispatchers.find(k->mouse ? "mouse" : k->handler);
if (SPECIALTRIGGERED && !pressed)
std::erase_if(m_vPressedSpecialBinds, [&](const auto& other) { return other == &k; });
std::erase_if(m_vPressedSpecialBinds, [&](const auto& other) { return other == k; });
else if (SPECIALDISPATCHER && pressed)
m_vPressedSpecialBinds.push_back(&k);
m_vPressedSpecialBinds.emplace_back(k);
// Should never happen, as we check in the ConfigManager, but oh well
if (DISPATCHER == m_mDispatchers.end()) {
Debug::log(ERR, "Invalid handler in a keybind! (handler {} does not exist)", k.handler);
Debug::log(ERR, "Invalid handler in a keybind! (handler {} does not exist)", k->handler);
} else {
// call the dispatcher
Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {})", modmask, key.keyName, key.keysym);
@@ -718,29 +744,27 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
m_iPassPressed = (int)pressed;
// if the dispatchers says to pass event then we will
if (k.handler == "mouse")
res = DISPATCHER->second((pressed ? "1" : "0") + k.arg);
if (k->handler == "mouse")
res = DISPATCHER->second((pressed ? "1" : "0") + k->arg);
else
res = DISPATCHER->second(k.arg);
res = DISPATCHER->second(k->arg);
m_iPassPressed = -1;
if (k.handler == "submap") {
if (k->handler == "submap") {
found = true; // don't process keybinds on submap change.
break;
}
}
if (k.repeat) {
m_pActiveKeybind = &k;
m_pActiveKeybindEventSource = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, repeatKeyHandler, &m_pActiveKeybind);
if (k->repeat) {
const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock();
wl_event_source_timer_update(m_pActiveKeybindEventSource, PACTIVEKEEB->repeatDelay);
m_vActiveKeybinds.emplace_back(k);
m_pRepeatKeyTimer->updateTimeout(std::chrono::milliseconds(PACTIVEKEEB->repeatDelay));
}
if (!k.nonConsuming)
if (!k->nonConsuming)
found = true;
}
@@ -761,17 +785,17 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP
void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint32_t doesntHaveCode) {
// shadow disables keybinds after one has been triggered
for (auto& k : m_lKeybinds) {
for (auto& k : m_vKeybinds) {
bool shadow = false;
if (k.handler == "global" || k.transparent)
if (k->handler == "global" || k->transparent)
continue; // can't be shadowed
if (k.multiKey && (mkBindMatches(k) == MK_FULL_MATCH))
if (k->multiKey && (mkBindMatches(k) == MK_FULL_MATCH))
shadow = true;
else {
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
const auto KBKEY = xkb_keysym_from_name(k->key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY);
for (auto const& pk : m_dPressedKeys) {
@@ -784,7 +808,7 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint3
}
}
if (pk.keycode != 0 && pk.keycode == k.keycode) {
if (pk.keycode != 0 && pk.keycode == k->keycode) {
shadow = true;
if (pk.keycode == doesntHaveCode && doesntHaveCode != 0) {
@@ -795,13 +819,13 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint3
}
}
k.shadowed = shadow;
k->shadowed = shadow;
}
}
bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
// Handles the CTRL+ALT+FX TTY keybinds
if (!(keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12))
if (keysym < XKB_KEY_XF86Switch_VT_1 || keysym > XKB_KEY_XF86Switch_VT_12)
return false;
// beyond this point, return true to not handle anything else.
@@ -916,7 +940,7 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo
sigset_t set;
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);
sigprocmask(SIG_SETMASK, &set, nullptr);
grandchild = fork();
if (grandchild == 0) {
@@ -942,7 +966,7 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo
read(socket[0], &grandchild, sizeof(grandchild));
close(socket[0]);
// clear child and leave grandchild to init
waitpid(child, NULL, 0);
waitpid(child, nullptr, 0);
if (grandchild < 0) {
Debug::log(LOG, "Fail to create the second fork");
return 0;
@@ -973,7 +997,7 @@ SDispatchResult CKeybindManager::kill(std::string args) {
}
void CKeybindManager::clearKeybinds() {
m_lKeybinds.clear();
m_vKeybinds.clear();
}
static SDispatchResult toggleActiveFloatingCore(std::string args, std::optional<bool> floatState) {
@@ -1010,8 +1034,12 @@ static SDispatchResult toggleActiveFloatingCore(std::string args, std::optional<
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW);
}
g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID());
g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID());
if (PWINDOW->m_pWorkspace) {
PWINDOW->m_pWorkspace->updateWindows();
PWINDOW->m_pWorkspace->updateWindowData();
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -1174,12 +1202,12 @@ SDispatchResult CKeybindManager::changeworkspace(std::string args) {
const static auto PWARPONWORKSPACECHANGE = CConfigValue<Hyprlang::INT>("cursor:warp_on_change_workspace");
if (*PWARPONWORKSPACECHANGE) {
if (*PWARPONWORKSPACECHANGE > 0) {
auto PLAST = pWorkspaceToChangeTo->getLastFocusedWindow();
auto HLSurface = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock());
if (PLAST && (!HLSurface || HLSurface->getWindow()))
PLAST->warpCursor();
PLAST->warpCursor(*PWARPONWORKSPACECHANGE == 2);
}
return {};
@@ -1218,15 +1246,15 @@ SDispatchResult CKeybindManager::fullscreenStateActive(std::string args) {
clientMode = std::stoi(ARGS[1]);
} catch (std::exception& e) { clientMode = -1; }
const sFullscreenState STATE = sFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal),
const SFullscreenState STATE = SFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal),
.client = (clientMode != -1 ? (eFullscreenMode)clientMode : PWINDOW->m_sFullscreenState.client)};
if (internalMode != -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client)
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = FSMODE_NONE});
g_pCompositor->setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = FSMODE_NONE, .client = FSMODE_NONE});
else if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal)
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = PWINDOW->m_sFullscreenState.client});
g_pCompositor->setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = FSMODE_NONE, .client = PWINDOW->m_sFullscreenState.client});
else if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client)
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = FSMODE_NONE});
g_pCompositor->setWindowFullscreenState(PWINDOW, SFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = FSMODE_NONE});
else
g_pCompositor->setWindowFullscreenState(PWINDOW, STATE);
@@ -1279,7 +1307,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) {
g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace);
}
POLDWS->m_pLastFocusedWindow = g_pCompositor->getFirstWindowOnWorkspace(POLDWS->m_iID);
POLDWS->m_pLastFocusedWindow = POLDWS->getFirstWindow();
if (pWorkspace->m_bIsSpecialWorkspace)
pMonitor->setSpecialWorkspace(pWorkspace);
@@ -1346,6 +1374,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
SDispatchResult CKeybindManager::moveFocusTo(std::string args) {
static auto PFULLCYCLE = CConfigValue<Hyprlang::INT>("binds:movefocus_cycles_fullscreen");
static auto PMONITORFALLBACK = CConfigValue<Hyprlang::INT>("binds:window_direction_monitor_fallback");
static auto PGROUPCYCLE = CConfigValue<Hyprlang::INT>("binds:movefocus_cycles_groupfirst");
char arg = args[0];
if (!isDirection(args)) {
@@ -1365,6 +1394,21 @@ SDispatchResult CKeybindManager::moveFocusTo(std::string args) {
(arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) :
g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
// Prioritize focus change within groups if the window is a part of it.
if (*PGROUPCYCLE) {
if (!PLASTWINDOW->m_sGroupData.pNextWindow.expired()) {
if (arg == 'l' && PLASTWINDOW != PLASTWINDOW->getGroupHead()) {
PLASTWINDOW->setGroupCurrent(PLASTWINDOW->getGroupPrevious());
return {};
}
else if (arg == 'r' && PLASTWINDOW != PLASTWINDOW->getGroupTail()) {
PLASTWINDOW->setGroupCurrent(PLASTWINDOW->m_sGroupData.pNextWindow.lock());
return {};
}
}
}
// Found window in direction, switch to it
if (PWINDOWTOCHANGETO) {
switchToWindow(PWINDOWTOCHANGETO);
@@ -1732,7 +1776,7 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) {
// apply
// we make a copy because changeWindowFloatingMode might invalidate the iterator
std::deque<PHLWINDOW> ptrs;
std::vector<PHLWINDOW> ptrs;
for (auto const& w : g_pCompositor->m_vWindows)
ptrs.push_back(w);
@@ -1773,13 +1817,17 @@ SDispatchResult CKeybindManager::renameWorkspace(std::string args) {
if (FIRSTSPACEPOS != std::string::npos) {
int workspace = std::stoi(args.substr(0, FIRSTSPACEPOS));
std::string name = args.substr(FIRSTSPACEPOS + 1);
g_pCompositor->renameWorkspace(workspace, name);
} else {
g_pCompositor->renameWorkspace(std::stoi(args), "");
}
if (const auto& PWS = g_pCompositor->getWorkspaceByID(workspace); PWS)
PWS->rename(name);
else
return {.success = false, .error = "No such workspace"};
} else if (const auto& PWS = g_pCompositor->getWorkspaceByID(std::stoi(args)); PWS)
PWS->rename("");
else
return {.success = false, .error = "No such workspace"};
} catch (std::exception& e) {
Debug::log(ERR, "Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what());
return {.success = false, .error = std::format("Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what())};
Debug::log(ERR, R"(Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. "{}": "{}")", args, e.what());
return {.success = false, .error = std::format(R"(Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. "{}": "{}")", args, e.what())};
}
return {};
@@ -1849,7 +1897,7 @@ SDispatchResult CKeybindManager::moveWorkspaceToMonitor(std::string args) {
}
SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
auto workspaceID = getWorkspaceIDNameFromString(args).id;
auto [workspaceID, workspaceName] = getWorkspaceIDNameFromString(args);
if (workspaceID == WORKSPACE_INVALID) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!");
return {.success = false, .error = "focusWorkspaceOnCurrentMonitor invalid workspace!"};
@@ -1865,7 +1913,7 @@ SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args
auto pWorkspace = g_pCompositor->getWorkspaceByID(workspaceID);
if (!pWorkspace) {
pWorkspace = g_pCompositor->createNewWorkspace(workspaceID, PCURRMONITOR->ID);
pWorkspace = g_pCompositor->createNewWorkspace(workspaceID, PCURRMONITOR->ID, workspaceName);
// we can skip the moving, since it's already on the current monitor
changeworkspace(pWorkspace->getConfigName());
return {};
@@ -2043,9 +2091,9 @@ SDispatchResult CKeybindManager::circleNext(std::string arg) {
if (g_pCompositor->m_pLastWindow.expired()) {
// if we have a clear focus, find the first window and get the next focusable.
if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()) > 0) {
const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID());
const auto PWS = g_pCompositor->m_pLastMonitor->activeWorkspace;
if (PWS && PWS->getWindows() > 0) {
const auto PWINDOW = PWS->getFirstWindow();
switchToWindow(PWINDOW);
}
@@ -2091,7 +2139,7 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) {
}
if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto FSWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
const auto FSWINDOW = PWORKSPACE->getFullscreenWindow();
const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
if (PWINDOW->m_bIsFloating) {
@@ -2110,6 +2158,10 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) {
if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned)
g_pCompositor->setWindowFullscreenClient(PWINDOW, FSMODE);
// warp the position + size animation, otherwise it looks weird.
PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealSize.warp();
}
} else
g_pCompositor->focusWindow(PWINDOW);
@@ -2147,8 +2199,8 @@ SDispatchResult CKeybindManager::setSubmap(std::string submap) {
return {};
}
for (auto const& k : g_pKeybindManager->m_lKeybinds) {
if (k.submap == submap) {
for (const auto& k : g_pKeybindManager->m_vKeybinds) {
if (k->submap == submap) {
m_szCurrentSelectedSubmap = submap;
Debug::log(LOG, "Changed keybind submap to {}", submap);
g_pEventManager->postEvent(SHyprIPCEvent{"submap", submap});
@@ -2248,7 +2300,7 @@ SDispatchResult CKeybindManager::sendshortcut(std::string args) {
const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]);
const auto KEY = ARGS[1];
uint32_t keycode = 0;
bool isMouse = 0;
bool isMouse = false;
// similar to parseKey in ConfigManager
if (isNumber(KEY) && std::stoi(KEY) > 9)
@@ -2257,7 +2309,7 @@ SDispatchResult CKeybindManager::sendshortcut(std::string args) {
keycode = std::stoi(KEY.substr(5));
else if (KEY.compare(0, 6, "mouse:") == 0 && isNumber(KEY.substr(6))) {
keycode = std::stoi(KEY.substr(6));
isMouse = 1;
isMouse = true;
if (keycode < 272) {
Debug::log(ERR, "sendshortcut: invalid mouse button");
return {.success = false, .error = "sendshortcut: invalid mouse button"};
@@ -2605,9 +2657,9 @@ SDispatchResult CKeybindManager::alterZOrder(std::string args) {
}
if (POSITION == "top")
g_pCompositor->changeWindowZOrder(PWINDOW, 1);
g_pCompositor->changeWindowZOrder(PWINDOW, true);
else if (POSITION == "bottom")
g_pCompositor->changeWindowZOrder(PWINDOW, 0);
g_pCompositor->changeWindowZOrder(PWINDOW, false);
else {
Debug::log(ERR, "alterZOrder: bad position: {}", POSITION);
return {.success = false, .error = "alterZOrder: bad position: {}"};
@@ -2892,6 +2944,9 @@ SDispatchResult CKeybindManager::event(std::string args) {
return {};
}
#include <utility>
#include <type_traits>
SDispatchResult CKeybindManager::setProp(std::string args) {
CVarList vars(args, 3, ' ');
@@ -2930,13 +2985,13 @@ SDispatchResult CKeybindManager::setProp(std::string args) {
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphaoverride") {
PWINDOW->m_sWindowData.alpha =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL).value_or(0)}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactiveoverride") {
PWINDOW->m_sWindowData.alphaInactive =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL).value_or(0)}, PRIORITY_SET_PROP);
} else if (PROP == "alphafullscreenoverride") {
PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL).value_or(0)}, PRIORITY_SET_PROP);
} else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") {
CGradientValueData colorData = {};
if (vars.size() > 4) {
@@ -2945,10 +3000,18 @@ SDispatchResult CKeybindManager::setProp(std::string args) {
if (TOKEN.ends_with("deg"))
colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0);
else
colorData.m_vColors.push_back(configStringToInt(TOKEN));
configStringToInt(TOKEN).and_then([&colorData](const auto& e) {
colorData.m_vColors.push_back(e);
return std::invoke_result_t<decltype(::configStringToInt), const std::string&>(1);
});
}
} else if (VAL != "-1")
colorData.m_vColors.push_back(configStringToInt(VAL));
configStringToInt(VAL).and_then([&colorData](const auto& e) {
colorData.m_vColors.push_back(e);
return std::invoke_result_t<decltype(::configStringToInt), const std::string&>(1);
});
colorData.updateColorsOk();
if (PROP == "activebordercolor")
PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
@@ -2961,15 +3024,21 @@ SDispatchResult CKeybindManager::setProp(std::string args) {
else if (VAL == "unset")
pWindowDataElement->unset(PRIORITY_SET_PROP);
else
*pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP);
*pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL).value_or(0), PRIORITY_SET_PROP);
} else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) {
if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else
*(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP);
} else {
else if (const auto V = configStringToInt(VAL); V)
*(search->second(PWINDOW)) = CWindowOverridableVar((int)*V, PRIORITY_SET_PROP);
} else if (auto search = g_pConfigManager->mfWindowProperties.find(PROP); search != g_pConfigManager->mfWindowProperties.end()) {
if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else {
const auto V = std::stof(VAL);
*(search->second(PWINDOW)) = CWindowOverridableVar(V, PRIORITY_SET_PROP);
}
} else
return {.success = false, .error = "Prop not found"};
}
} catch (std::exception& e) { return {.success = false, .error = std::format("Error parsing prop value: {}", std::string(e.what()))}; }
g_pCompositor->updateAllWindowsAnimatedDecorationValues();

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