Compare commits

..

212 Commits

Author SHA1 Message Date
Vaxry
9958d29764 version: bump to 0.49.0 2025-05-08 21:15:18 +01:00
Vaxry
239cdd67fd socket2: fix order of window events on map (#10341) 2025-05-08 22:10:31 +02:00
s1dd
f01e3043b8 desktop: cleanup code and use std::ranges (#10289) 2025-05-08 21:01:49 +02:00
Vaxry
04c98abd1f layout: properly assign workspace and monitor when moving a child to the parent (#10338) 2025-05-08 21:00:28 +02:00
nyx
53bfb92d65 layout: allow interacting with pinned windows when fullscreened (#10326)
* layout: allow interacting with pinned windows when fullscreened

* IHyprLayout: format code

* e
2025-05-08 20:59:51 +02:00
Mihai Fufezan
2b3cac018e flake.lock: update 2025-05-08 20:37:36 +03:00
Vaxry
f909b0f114 opengl: fix legacyrenderer 2025-05-08 18:22:44 +01:00
MightyPlaza
fa1e343b04 compositor: set fullscreenstate on movetoworkspace (#10303)
modified:   src/managers/KeybindManager.cpp
2025-05-08 18:29:47 +02:00
davc0n
22b12e3013 refactor: cshader class to sshader struct (#10324) 2025-05-08 00:07:35 +02:00
Mihai Fufezan
7a971735af flake.lock: update 2025-05-07 21:51:59 +03:00
Tom Englund
6abb5b0c7e renderer: precompute fullalpha (#10319)
precompute it once instead of calculating it every single call, was showing
up as a lot of time wasted in profiling.
2025-05-07 19:02:07 +02:00
Tom Englund
0dfcba9825 DMABuffer: reserve vector and avoid UB (#10317)
actually reserve the vector instead of initializing it with the
m_attrs.fd.size() adding 4 invalid fd entries, and later emplace_back
the valid ones.

sync_merge_data name is defined as char name[32] a fixed size array, and
c++ technically doesnt allow assigning string literals directly to array
fields in aggregate initializers, it may compile but is technically
undefined behaviour or ill formed. zero initalise it and use
std::ranges::copy_n instead.
2025-05-07 18:15:27 +02:00
davc0n
e5df8cdc62 xwayland: refactor class member vars (#10312)
* xwayland: refactor class member vars

* xwayland: fix pure wayland build
2025-05-07 15:21:44 +02:00
Vaxry
f8bbe5124c hyprpm: clean up root access and properly check input (#10304)
* manifest: reject bad names from parsing

* sys: restructure root functions
2025-05-06 22:43:08 +02:00
Vaxry
948277895e popup: damage old size on unmap as well as new (#10306)
fixes #10305

chromium for some reason sets the popup size to like 8x8 at the same time as unmapping
2025-05-06 21:49:20 +02:00
Zebra2711
708a7c24ef hyprpm: add missing return (#10299)
Add a missing return statement after handling the first superuser binary in the `dropSudo` function

Fixes: 1c530cb

Co-authored-by: Zebra2711 <zebra2711@users.noreply.github.com>
2025-05-06 14:53:28 +02:00
CyrenArkade
1ce614dfc0 animations: Add option for animating workspaces as if the first and last were adjacent (#10277)
* add option for animating workspaces as if the first and last were adjacent

* change wraparound detection to use IDs instead of dispatcher

* move shouldWraparound from MiscFunctions to Monitor
2025-05-06 03:54:27 +02:00
Jack Barnes
930eeac900 window: use stored size for new floating window when persistentsize is set (#10212)
* fix(window): use stored size for new floating window when persistentsize is set. fix hyprwm#9422.

* fix: replace `std::any_of` with `std::ranges:any_of`

* fix: use initialClass and initialTitle when storing sizes on close

* fix: add `xdgTag` as a new indicator

* fix: no {}

* fix: format with clang-format
2025-05-06 03:53:43 +02:00
shane blackthorne
ec93f8a1cd socket2: add monitorremovedv2 event (#10229) 2025-05-06 03:52:36 +02:00
davc0n
997fefbc11 render: refactor class member vars (#10292)
* render: refactor class member vars

* render: fix clang format
2025-05-05 23:44:49 +02:00
Vaxry
c7eb141098 renderer: always try to apply a mode if pixel size is invalid (#10291) 2025-05-05 23:40:37 +02:00
Vaxry
1f50cdfa8b hyprpm: wrap sudo cmd in quotes
ref #10288
2025-05-05 13:09:00 +01:00
s1dd
1c530cbc66 hyprpm: Minor optimizations and refactor of helpers and progress bar (#10246)
* hyprpm: optimize sys.cpp

* hyprpm: refine progress bar logic

* chore: fix fetchSuperuserBins

* chore: modify one line if/else statements

* chore: fix if/else statements

* chore: follow naming convention for const vars

* chore: revert shell escape logic
2025-05-05 04:22:22 +02:00
davc0n
9cd5b25745 protocols: refactor class member vars (u-z) (#10282)
* protocols: refactor class member vars (u-z)

* protocols: fix clang format
2025-05-04 23:39:00 +02:00
phonetic112
78ff20ddf0 workspaces: Fix empty flag not selecting active workspace (#10237) 2025-05-04 19:22:41 +02:00
davc0n
2626f89ea6 protocols: refactor class member vars (n-t) (#10273) 2025-05-04 19:21:36 +02:00
davc0n
adbae0f74d protocols: refactor class member vars (a-m) (#10265) 2025-05-04 00:13:29 +02:00
davc0n
46ac115bd1 protocols: refactor class member vars (types) (#10261) 2025-05-03 18:54:50 +02:00
Honkazel
3465efcdc1 internal: Use vecnotinrect instead of !vecinrect (#10262)
* monitor: use vecnotinrect

* inputmanager: vecnotinrect

* clang format
2025-05-03 18:54:15 +02:00
Virt
cdf5736f1a layerrules: fix abovelock interactivity for touch input (#10253) 2025-05-03 16:07:02 +02:00
davc0n
2d6ca96e07 plugins: refactor class member vars (#10257) 2025-05-03 16:06:24 +02:00
davc0n
d9cad5e1b6 protocols: refactor class member vars (core) (#10259) 2025-05-03 16:02:49 +02:00
Vaxry
0c736217a7 configmgr: fix CConfigValue<> from plugins 2025-05-02 17:53:55 +01:00
Vaxry
77ecf09506 internal: fix name confusion in SAlphaValue
fixes #10251
2025-05-02 16:29:15 +01:00
vaxerski
f1ac1847ff [gha] Nix: update inputs 2025-05-02 15:08:46 +00:00
davc0n
ce821294e2 managers: refactor class member vars (#10242) 2025-05-02 17:07:20 +02:00
Vaxry
6f174a9e08 renderer: render fading out floating windows over fs 2025-05-02 00:16:17 +01:00
davc0n
5b3e489108 inputs: refactor class member vars (#10230) 2025-05-01 23:57:11 +02:00
Jan Beich
2670b8f772 hyprpm: add missing include for libc++ after 858c0e26d1 (#10234)
hyprpm/src/core/DataState.cpp:80:23: error: implicit instantiation of undefined template 'std::basic_stringstream<char>'
   80 |     std::stringstream ss;
      |                       ^
hyprpm/src/core/DataState.cpp:149:23: error: implicit instantiation of undefined template 'std::basic_stringstream<char>'
  149 |     std::stringstream ss;
      |                       ^
hyprpm/src/core/DataState.cpp:229:31: error: implicit instantiation of undefined template 'std::basic_stringstream<char>'
  229 |             std::stringstream ss;
      |                               ^
/usr/include/c++/v1/__fwd/sstream.h:30:28: note: template is declared here
   30 | class _LIBCPP_TEMPLATE_VIS basic_stringstream;
      |                            ^
2025-05-01 20:48:13 +02:00
Vaxry
858c0e26d1 hyprpm: move to system directories for storing plugins (#10211) 2025-05-01 18:00:26 +02:00
Zetta1 Reid0
b5ef049ea1 master: Change center_master_slaves_on_right to center_master_fallback (#10201)
* Change center_master_slaves_on_right  to center_master_fallback
2025-05-01 13:29:06 +02:00
davc0n
615e0dae46 layouts: refactor class member vars (#10228) 2025-05-01 13:27:07 +02:00
davc0n
ce4766772d hyprerror: refactor class member vars (#10227) 2025-05-01 13:26:43 +02:00
Vaxry
8d6618104e cmake: ignore Wclobbered
fails build otherwise
2025-04-30 23:06:40 +01:00
davc0n
50e1bec85f helpers: refactor class member vars (#10218) 2025-04-30 23:45:20 +02:00
Vaxry
b8a204c21d ci: minor fixes to glaze 2025-04-30 22:43:37 +01:00
Ikalco
2ee5118d7a render: properly release rendered buffers (#9807)
* cleanup eglSync

* properly release buffers in renderer

* add renderingDoneCallback and use it in screencopy

* use static constructor for CEGLSync
2025-04-30 18:35:25 +02:00
Vaxry
5d005f11fa xdg-bell: fix wrong resource cast 2025-04-30 14:07:23 +01:00
Vaxry
54c89104de DonationNag: ask after each major update (#10213)
This changes how the donation nag timing works.

The donation nag will now appear:

- after a major update (e.g. 48 -> 49)*
- once in late july
- once in december

however, a donation nag will never pop up more than once a month. So, if there is an update on the 26th of November, and you get a popup on the 28th, you will not get one in december.

This is of course still disableable in your config.
2025-04-30 14:47:35 +02:00
Mihai Fufezan
b2ad21a65c flake.lock: update 2025-04-30 09:26:58 +03:00
Vaxry
72cb5d24b6 permissions: disable automatic reloading of permissions from cfg
security reasons, avoid reading them live. Ideally we'd lock them behind sudo, but we can't do that.
2025-04-30 00:35:32 +01:00
Vaxry
9868b18378 input: don't use pointer hold logic for unmapped surfs
fixes #10215
2025-04-30 00:31:21 +01:00
Sander
208f4c48db config: use natural increase and decrease of brightness for default cfg (#10210)
* feat(config): hyprland natural brightness

* feat(config): natural increase and decrease of brightness
2025-04-30 01:10:47 +02:00
Vaxry
4506871310 xdg-bell: avoid crashes on null toplevel 2025-04-30 00:10:07 +01:00
Vaxry
6483f4ec22 screencopy: don't render cursor when frame doesn't want it 2025-04-29 22:02:55 +01:00
UjinT34
ae1fe860ff renderer: add render:send_content_type setting (#9851) 2025-04-29 22:09:14 +02:00
UjinT34
49974d5e34 cm: Use precomputed primaries conversion (#9814) 2025-04-29 21:29:40 +02:00
Vaxry
94bc132084 xdg-bell/xdg-tag: fix moved resource usage 2025-04-29 19:49:13 +01:00
davc0n
e9c3fcbb64 devices: refactor class member vars (#10206) 2025-04-29 19:51:07 +02:00
Vaxry
40147d3a3f asyncdialogbox: fix missing header 2025-04-29 18:37:21 +01:00
Vaxry
23ecce0e7a protocols: add support for xdg-system-bell-v1 2025-04-29 18:32:21 +01:00
Vaxry
465e3d979d window: make AsyncDialogBoxes not closeable
we don't want the user to accidentally close a popup for permissions or ANR. They can dismiss them by clicking an appropriate option.
2025-04-29 18:20:06 +01:00
Vaxry
b10a43dabc windowrules: add noclosefor
fixes #10027
2025-04-29 18:14:02 +01:00
Vaxry
5bd7ff884d permissions: add perms for plugin loading (#10184)
Adds permission management for loading plugins

---------

Co-authored-by: Jan Beich <jbeich@FreeBSD.org>
2025-04-29 18:59:43 +02:00
davc0n
2118440488 windows: refactor class member vars (#10168) 2025-04-28 22:25:22 +02:00
Vaxry
c505eb55ff screencopy: support hw cursors while sharing with cursor 2025-04-28 20:18:02 +01:00
Vaxry
f5c5cfa960 keybindmgr: fixup bindn regression
fixes #10195
2025-04-28 00:18:51 +01:00
Vaxry
0302bfdc22 async: add Promise and use it for AsyncDialogBox 2025-04-27 13:28:06 +01:00
Vaxry
4f868a1f3c SECURITY: init security policy
fixes #9921
2025-04-27 00:07:00 +02:00
nyx
94c55fe909 helpers: properly support next/prev for workspace switching (#10074) 2025-04-26 23:52:07 +02:00
Vaxry
742bce016c decorationPositioner: update posinfo on window update
fixes #10175
2025-04-25 16:09:11 +01:00
Virt
4cf62c114e layerrules: add abovelock to render above lockscreen (#9793) 2025-04-25 16:38:31 +02:00
Jason
41f5f67f6c window: Fix order of urgency flag and event emission (#10163) 2025-04-25 02:37:49 +02:00
davc0n
02d7badd15 workspaces: refactor class member vars (#10167) 2025-04-25 02:37:12 +02:00
davc0n
0e80ecc534 layers: refactor class member vars (#10149)
* layers: refactor class member vars

* popups: rename m_WLSurface to m_wlSurface
2025-04-24 20:49:49 +02:00
M Matthew Hydock
be6268a7ec groupbar: Add options for setting group bar title font weight (and indicator gap) (#9617) 2025-04-24 20:48:08 +02:00
WhySoBad
a9549dbca0 protocols: add Hyprland toplevel mapping implementation (#9775) 2025-04-24 18:10:57 +02:00
Vaxry
b06fbdb743 dwindle: use idealIgnoreReserved for moveWindowTo bbs
fixes #10005
2025-04-23 22:31:14 +01:00
davc0n
241a4935a2 compositor: refactor class member vars (#10141) 2025-04-22 15:23:29 +02:00
Mihai Fufezan
3577a6be31 nix/overlays: add w-p 1.43 2025-04-22 11:03:27 +03:00
Mihai Fufezan
2e540e4ec4 flake.lock: update 2025-04-22 11:00:49 +03:00
Vaxry
a4f7d7c594 protocols: add xdg_toplevel_tag_v1 support
Adds a new windowrule to target windows by xdgTag, xdgtag:
2025-04-21 22:30:27 +01:00
nyx
55e953b383 InputManager: add nofollowmouse (#9994)
* InputManager: add nofollowmouse

with this, focus_follows_mouse=1 acts like focus_follows_mouse=2 on the specific windows defined by the user

* e

* e

biggest e of all time
2025-04-21 20:48:27 +02:00
nyx
d29723cb76 keybinds: allow executing binds not bound to a key (#10102) 2025-04-21 20:47:14 +02:00
davc0n
400dd16072 debug: refactor class member vars (#10130) 2025-04-21 20:42:02 +02:00
Andrei V
a3b96961a2 tablet: naive window refocusing (#10110)
Signed-off-by: Andrei V <andrei@ptaxa.net>
2025-04-21 00:32:31 +02:00
Vaxry
a3d32f3b70 hyprpm: fix format 2025-04-20 23:23:17 +01:00
davc0n
4d14bcb02f config: Refactor class member vars (#10124)
* Refactor config classes vars

* Fix clang format errors
2025-04-20 20:39:33 +02:00
Vaxry
9b4060f09b hyprpm: extend dep list 2025-04-20 16:54:28 +01:00
syuzuki
867bc86089 compositor: fix getMonitorInDirection skipping active monitor (#10114) 2025-04-20 04:22:21 +02:00
Bruno Krügel
f48ee7a3d1 protocols: ensure PointerConstraints activation occurs only after attched to InputManager (#10096) 2025-04-19 01:16:30 +02:00
fazzi
51afc2c291 ctm: enable fade animation on nvidia driver versions 575 and above (#10095)
* ctm: enable fade animation on nvidia driver versions 575 and above

* format if statement without braces; handle potential throw when checking for nvidia version file
2025-04-18 21:44:54 +02:00
vaxerski
02f7da2bf2 [gha] Nix: update inputs 2025-04-18 15:39:22 +00:00
Lee Bousfield
7631d4c73f render, helpers: Call OpenGL destroyMonitorResources on disconnect (#10111)
* render, helpers: Call OpenGL destroyMonitorResources on disconnect

* helpers: Add opengl null check
2025-04-18 17:37:51 +02:00
raf
ddae3036ca ci: close unwanted issues automatically (#10106)
* ci: close unwanted issues automatically

You want it, it's yours my friend.

* ci/close-issues: simplify

* ci/close-issues: try to handle large number of issues

* ci/close-issues: fix 'vaxerski'
2025-04-17 22:33:05 +02:00
nyx
225e13c3cc InputManager: add config option to disable keybinds per device (#10064) 2025-04-17 02:19:10 +02:00
Lee Bousfield
3fa6320a39 desktop: Damage subsurface when position changes (#10094) 2025-04-16 17:49:01 +02:00
Vaxry
1ae7e2164c xcursormgr: include <variant>
ref #10093
2025-04-16 13:49:41 +01:00
Vaxry
877fb5b93a time: move to stl's clocks and move timer 2025-04-16 01:37:48 +01:00
Ikalco
0e521788bc core: wait for dmabuf readiness (#9806)
* add doOnReadable to event loop manager

* move syncTimeline addWaiter to doOnReadable

* wait on dmabuf buffers to be readable

* don't over synchronize in scanout, also give present feedback on same buffer commit
2025-04-16 01:02:31 +02:00
MightyPlaza
ffd6cf65e4 windowrules: allow incrementing window props (#9566) 2025-04-16 01:00:40 +02:00
Mihai Fufezan
8b7b169043 flake.lock: update 2025-04-14 18:58:37 +03:00
Nathan Ollerenshaw
533bc5115e monitors: fix disconnected monitors are reconnected to an empty workspace (#9874)
---------

Co-authored-by: nyx <nnyyxxxx@protonmail.com>
2025-04-14 11:07:53 +02:00
psyvern
99ab3e19d9 framebuffer: Fix framebuffer size check (#10068) 2025-04-13 22:40:15 +02:00
Vaxry
f4e19d3f1e layerSurface: warp position and size before taking a snapshot (#10054) 2025-04-13 17:56:20 +02:00
nyx
06469b3391 IHyprLayout: center floating window at cursor when picked up from fullscreen (#10063) 2025-04-13 17:32:53 +02:00
nyx
303a10d27c IHyprLayout: respect minimum window size (#10017)
* IHyprLayout: respect minimum window size

this prevents window warping, before we were not respecting the minimum size which caused the window to move suddenly, even though it would be sized to its minimum size.
2025-04-13 01:03:03 +02:00
rszyma
4d85e7996d dwindle: ignore fullscreen window for positioning when use_active_for_splits=false (#9838)
* fix(dwindle): ignore fullscreen window for positioning when use_active_for_splits=false

* rename NON_FULLSCREEN -> SKIP_FULLSCREEN_PRIORITY
2025-04-13 00:58:38 +02:00
Ikalco
2da4f427ea compositor/surface: fix surface opaque and input regions not being updated (#10055) 2025-04-12 18:58:29 +02:00
Vaxry
a17cea8b8c asyncDialogBox: fix missing pid
fixes #10056
2025-04-12 17:47:22 +01:00
alaricljs
6538970087 binds: add drag_threshold for click/drag isolation (#9839)
---------

Co-authored-by: Leeman <lstrout@enlj.com>
2025-04-12 16:43:13 +02:00
Lee Bousfield
0399e64274 screencopy: Handle explicit sync failure (#10050) 2025-04-12 16:38:46 +02:00
Vaxry
382f0f23f1 pass: revert "remove renderer finalDamage since it's unused (#9996)" (#10039)
This reverts commit 0a7e2cb152.
2025-04-11 00:34:50 +02:00
Aaron Blasko
b83c9f5c6f cmake: do not install version.h.in (#10035) 2025-04-11 00:31:07 +02:00
Virt
d775686380 input: add warp_on_toggle_special (#9945) 2025-04-10 14:54:24 +02:00
Ikalco
0dc531c4a7 core: fix crash in data device on shutdown (#9997) 2025-04-09 18:08:42 +02:00
Ikalco
0a7e2cb152 pass: remove renderer finalDamage since it's unused (#9996) 2025-04-09 17:50:06 +02:00
Vaxry
4f991610d0 watchdog: remove watchdog
it has been unused for a while now
2025-04-09 01:48:21 +01:00
nyx
ea852965ff xdg-shell: fix some null refs (#9992) 2025-04-08 19:43:15 +02:00
Vaxry
260d8e1f71 Permission Manager: add permission management for screencopy (#9930) 2025-04-08 19:39:53 +02:00
nyx
642f394eb3 xwayland: sync primary selection with wayland (#9952) 2025-04-08 17:36:29 +02:00
Vaxry
b15c2bfff6 CursorManager: Store cursor pixel data retrieved from X/HC as a copy (#9986)
Instead of storing pointers as refs (which could randomly get invalid very easily) copy the data.
2025-04-07 21:08:16 +02:00
Ikalco
da86db43d4 core: refactor and improve surface commit (#9805)
* make CHLBufferReference not a SP anymore

* copy over release and acquire points in CHLBufferReference

* use CHLBufferReference in screencopy and toplevel export

TODO: use CHLBufferReference in direct scanout properly
      the only problem is the scanout buffer release timing,
      specifically the onBackendRelease mechanism

* cleanup SSurfaceState and surface pending commit tracking

* move surface code from DRMSyncobj, and move acquire to SSurfaceState

* use queue for comitted pending surface states like proto says

"The content update is placed in a queue until it becomes active." - wl_surface::commit

* drop, not release, prev buffer if 2nd buffer wl_surface.attach is sent

"A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor." - wl_surface::attach
2025-04-07 21:03:27 +02:00
Vaxry
70ae99f521 input/layers: Fix exclusive LS focus / refocus after unmap (#9984) 2025-04-07 20:52:11 +02:00
Jan Beich
a8eda7f978 helpers: add missing include for BSDs after 3c128679ee (#9982)
src/helpers/AsyncDialogBox.cpp:47:23: error: use of undeclared identifier 'read'
   47 |         while ((ret = read(m_pipeReadFd.get(), buf.data(), 1023)) > 0) {
      |                       ^
src/helpers/AsyncDialogBox.cpp:83:9: error: use of undeclared identifier 'pipe'
   83 |     if (pipe(outPipe)) {
      |         ^
src/helpers/AsyncDialogBox.cpp:110:5: error: use of undeclared identifier 'close'
  110 |     close(outPipe[1]);
      |     ^
2025-04-07 20:36:01 +02:00
kerty0
8a8f394da7 swipe: fix swiping onto a new workspace bound to another monitor (#8176) (#9927)
The previous code didn't check if the chosen new workspace was bound to another monitor, causing buggy behavior where workspace was simultaneously open and not.

The fix simply uses `r+1` for new workspace selection.

Also, the previous code would select rightmost workspace + 1, creating large gaps in workspace IDs in some scenarios. Example (`()` and `[]` indicate workspaces on different monitors):

`(1), 2, 3, 4, 5, 6, 7, 8, 9, [10]`

Swipe right on `()` monitor would create:

`(1), 2, 3, 4, 5, 6, 7, 8, 9, [10], (11)`

But with this commit:

`(1), (2), 3, 4, 5, 6, 7, 8, 9, [10]`
2025-04-07 14:46:31 +02:00
Virt
51838fb5f5 layout: properly track floating window position (#9937) 2025-04-06 23:41:27 +02:00
Vaxry
85f874d10f swipe: fix prev workspace remembering
fixes #9904
2025-04-06 22:35:26 +01:00
nyx
9b3925009a DataDevice: position icon at cursor hotspot (#9895)
* DataDevice: position icon at cursor hotspot

ref: https://wayland.app/protocols/wayland#wl_data_device:request:start_drag
2025-04-06 23:24:14 +02:00
Vaxry
3c128679ee helpers: Add an async dialog box impl (#9919)
Adds an async dialog box, way safer than our previous local solution for ANR
2025-04-06 17:31:58 +02:00
Vaxry
e96b8ce4cc window: send fractional scale on updateScaleTransform
fixes #9889
2025-04-06 00:30:13 +01:00
Maximilian Seidler
433b7881a3 compositor: fix crash when moving a workspace to a monitor with size 0x0 (#9848) 2025-04-06 00:54:29 +02:00
Vaxry
ed05f14300 ci: nuke stalebot 2025-04-05 19:28:42 +01:00
Vaxry
c62fb08da6 github: remove issue templates 2025-04-05 18:45:52 +01:00
Vaxry
8ba20fcae1 compositor: avoid crash on null window monitor move
ref #9809
2025-04-05 00:30:33 +01:00
Mihai Fufezan
ff97d18c4c flake.lock: update 2025-04-03 18:08:55 +00:00
Maximilian Seidler
5e8bb71785 ctm: fix crash when finishing ctm progress with a destroyed monitor (#9835) 2025-04-03 16:40:59 +02:00
Amadej Kastelic
b496e2c718 nix/module: load plugins using exec-once (#9836) 2025-04-03 10:43:06 +03:00
Arkady Buryakov
a41b8d5e97 groupbar: add text offset and upper gap settings (#9733)
* Groupbar: add keep_upper_gap setting to apply/remove outer gap offset to the upper side of groupbar

* Groupbar: add text_offset setting to adjust text vertical position in a group header
2025-04-02 22:26:46 +02:00
Armin
8654029f86 versionkeeper: create version file if not present (#9829) 2025-04-02 22:21:05 +02:00
nyx
a4e6c5d678 window: don't deactivate unfocused xwayland windows in groups (#9781)
* window: don't deactivate unfocused xwayland windows in groups

we dont want to deactivate unfocused xwayland windows because X is weird, keep the behavior for wayland windows
2025-04-02 00:51:37 +02:00
nyx
3a47c73f34 layout: center floating window at cursor when picked up from fullscreen (#9780)
* layout: center floating window at cursor when picked up from fullscreen

when picking up a floating window after it had been fullscreened before it would return to its previous position which looked ugly because the cursor could be no where near the windows original position, this patch makes it so that the window is returned to the users current cursor position

* E
2025-04-02 00:45:51 +02:00
X2E4VXpZKv
1f0fd79b91 internal: Don't force default cursor on config reload/monitor reconfigure (#9815) 2025-04-01 16:20:38 +02:00
Vaxry
d1a59ec39e renderer: render tiled fading out above other tiled windows
fixes #9717

closes #9796
2025-04-01 00:25:09 +01:00
Vaxry
4c987b20e2 makefile: fix find command in installheaders
fixes #9812
2025-03-31 17:13:27 +01:00
nyx
2309270752 anr: add config for ping number before popup shows up (#9782)
* anr: make pings configurable

makes the pings of the dialog popup configurable
2025-03-31 18:06:17 +02:00
Vaxry
79b526a041 socket2: add minimized event for foreign-wlr
ref #995
2025-03-30 22:38:30 +01:00
nyx
075bbecabd core: fix artifacts when fullscreening (#9778)
* core: fix artifacts when fullscreening

fixes an issue where fullscreening a floating window that is between two monitors causes artifacts to appear on the monitor where it did not become fullscreened on

* e
2025-03-30 23:28:12 +02:00
nyx
8aaffda969 core: fix null ref when resuming system (#9794)
* core: fix null ref when resuming system

* e
2025-03-30 23:18:04 +02:00
Shockingly Good
10a335631e solitary: Fix the non-working tearing #9429 (#9772)
Fixes the non-working tearing by removing the incorrect
opaqueness check for the windows.

Fixes #9429
2025-03-30 20:29:39 +02:00
Emad Elsaid
da2d7c3971 config: Fix matching monitor by description to allow space prefix (#9788) 2025-03-30 03:12:15 +02:00
LeviVanDerMaas
05eb0aa43d workspaces: Add binds:hide_special_on_workspace_change (#9728) 2025-03-30 03:11:39 +02:00
Tom Englund
fc7223edc0 synctimeline: check if fd is readable before wait (#9789)
a lot of the time the fd is already readable, and done. so just call the
waiter directly instead of making a waiter and adding it to the
eventloop.
2025-03-30 01:53:23 +01:00
Lee Bousfield
86c279d7d0 protocols: Don't update hdr metadata if image description is unchanged (#9776) 2025-03-30 01:25:27 +01:00
micha4w
46b00a4a86 makefile: add new shaders to make installheaders (#9783) 2025-03-30 01:25:02 +01:00
Tom Englund
4a79eea6dc opengl: check for g_pHyprOpengl pointer (#9791)
restore the pointer check to avoid null ptr dereference on compositor
destruction.
2025-03-29 21:52:27 +01:00
UjinT34
7374a023ef renderer/opengl: Extract shaders from source (#9600)
---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2025-03-29 01:19:35 +01:00
Lee Bousfield
a46576afc3 xwayland: Cleanup server startup and FDs (#9769) 2025-03-28 17:12:25 +01:00
Lee Bousfield
10035a85cc core: Don't damage the entire surface every frame (#9763)
* core: Don't damage the entire surface every frame

* core: Damage buffer on dims or transform change

* core: Use guards for scale and tr equality checks
2025-03-28 17:00:39 +01:00
Vaxry
c93140a5f1 surfacestate: reset buffer bit before applying to current
fixes #9759
2025-03-28 12:32:07 +00:00
Vaxry
5380cbcdda workspaces: minor fixes to persistence
fixes #9741
2025-03-27 14:00:29 +00:00
Tom Englund
9ea76428b6 internal: fix minor ubsan errors (#9743)
* opengl: check if g_pHyprOpengl exist

on compositor destruction we can hit a race where a CEGLSync destructs
and tries to call eglDestroySyncKHR on a null g_pHyprOpengl.

/src/render/OpenGL.cpp:3019:32: runtime error: member access within null pointer of type 'struct CHyprOpenGLImpl'
     #0 0x555565eed979 in CEGLSync::~CEGLSync() /src/render/OpenGL.cpp:3019
     #1 0x555565f6271e in std::default_delete<CEGLSync>::operator()(CEGLSync*)
     const /usr/lib/gcc/x86_64-pc-linux-gnu/14/include/g++-v14/bits/unique_ptr.h:93

* xdgshell: dont apply state on empty states

setsize can be called before a state has been added to pending,
resulting in calling ApplyState with a empty state.

/src/protocols/XDGShell.cpp:323:11: runtime error: null pointer passed as argument 2, which is declared to never be null
     #0 0x5555659bf67e in CXDGToplevelResource::applyState() /src/protocols/XDGShell.cpp:323
     #1 0x5555659bcedc in CXDGToplevelResource::setSize(Hyprutils::Math::Vector2D const&) /src/protocols/XDGShell.cpp:  256
     #2 0x555563eed0ef in Events::listener_commitWindow(void*, void*) /src/events/Windows.cpp:841
2025-03-26 18:22:44 +01:00
Vaxry
0cd04bd666 surfacestate: track and apply updated state
fixes #9729
2025-03-26 17:22:21 +00:00
Vaxry
1c2b9a9ce3 opengl: don't attempt to compile cm on gles3.0
also disable the error for the cm shader

fixes #9738
2025-03-26 14:28:19 +00:00
vaxerski
cec084c178 pass/rect: include clipBox in opaque calculations
ref #9730 ref #9709
2025-03-26 11:47:04 +00:00
vaxerski
c2ef8fcc00 groupbar: round boxes 2025-03-26 11:44:38 +00:00
Tom Englund
3fc3521a97 pass: remove unusued timeline in texpass (#9734)
remove unused timeline and waitpoint in texpass and especially remove
the passing it to renderTextureInternalWithDamage that implicitly
converted it to bool. setting discardActive and allowCustomUV
2025-03-26 02:22:09 +01:00
Arkady Buryakov
9a67354fa2 Groupbar: apply scaling factor to text (#9731) 2025-03-26 02:07:56 +01:00
nyx
f7ba86d1f3 keybinds: add sendkeystate dispatcher (#9599) 2025-03-25 00:59:13 +01:00
Vaxry
f3db1b172c decoration: bring back border_part_of_window
fixes #9683, now under decoration: though
2025-03-24 23:57:50 +00:00
Tom Englund
2a6d070774 xwl: dont close the fd to early (#9715)
dont close the fd until the wl_event_source is removed, so we dont get
another event triggered with an already closed fd.
2025-03-24 19:33:07 +01:00
Vaxry
aec69131cd seat: avoid sending null surfaces in leave/enter events
ref #9699
2025-03-24 14:10:47 +00:00
vaxerski
4b968e5bc1 [gha] Nix: update inputs 2025-03-24 12:57:34 +00:00
UjinT34
a852461c7d renderer: Simplify and fix hdr metadata setting (#9706)
* simplify and fix hdr metadata setting

* keep incorrect(?) cm skip till #9600
2025-03-24 13:56:07 +01:00
Mihai Fufezan
e4abf26069 Nix: add changes from Nixpkgs derivation 2025-03-23 18:19:34 +02:00
Mihai Fufezan
006bd9eef5 protocols/meson.build: use native wayland-scanner 2025-03-23 18:15:17 +02:00
Vaxry
5ee35f914f version: bump to 0.48.0 2025-03-23 14:56:13 +00:00
entailz
aa1bd647b1 core/Compositor.hpp: fix non-relative Texture import (#9703) 2025-03-23 14:49:10 +02:00
Lee Bousfield
fdb7ca6c8f core/compositor: Fix dropping cursor buffer data early (#9700) 2025-03-22 23:06:02 +01:00
UjinT34
6ab5a0befb renderer: fix cm_fs_passthrough (#9698) 2025-03-22 18:34:01 +01:00
Lee Bousfield
6384f4acf4 core/compositor: Correctly track SHM buffer damage (#9678) 2025-03-22 17:13:44 +01:00
Aaron Blasko
4600043a49 hyprpm: return 1 when plugins are outdated (#9694)
* hyprpm: return 1 when plugins are outdated

* clang-formatted
2025-03-22 17:01:35 +01:00
Lee Bousfield
279b06044c screencopy, render: Use explicit sync for screencopy (#9697)
* screencopy, render: Use explicit sync for screencopy

* screencopy: Check if explicit sync is enabled

* screencopy: Don't require explicit KMS enabled
2025-03-22 17:01:14 +01:00
Tom Englund
ccbdba7ee2 syncobj: refactor point timelines (#9689)
no need to store the resource, just store the csynctimeline as a shared
pointer and make the timeline own the syncobj fd.
2025-03-21 20:19:53 +01:00
UjinT34
c7f0519faf core: fix DS and VRR automation (#9334) 2025-03-21 14:33:07 +01:00
Lee Bousfield
7ea4fbf0ba types: Upgrade buffer ref from WP to SP (#9677) 2025-03-20 11:08:47 +00:00
Tom Englund
f6ca4bac51 syncobj: restore SHM buffer reset (#9675)
reset shm buffers early to mitigate stuttering animations, also reuse
the monitors eglSync and store the eglsync per monitor. this however
reintroduces flickering in dbeaver nonsyncobj application.
2025-03-20 11:39:55 +01:00
phonetic112
155eba57d8 groupbar: remove 2 pixel gap above groupbar (#9664) 2025-03-19 23:09:36 +01:00
Andrei V
7b10530a0d XWayland: restore the abstract socket, and make it optional (#9615)
* Revert "xwayland: don't create an abstract unix domain socket on linux (#8874)" (#9574)

This reverts commit 2b01a5bcf6.

* xwayland: make the abstract Unix domain socket optional (#9574)

* xwayland: extend the default permissions for a regular Unix domain socket (#9574)

* xwayland: a little refactoring for `createSocket`
2025-03-19 23:06:30 +01:00
Tom Englund
a25a214523 dmabuf: pop buffer on failure (#9620)
ensure it doesnt permanently gets stuck in the container on failure, pop
it from the container.
2025-03-19 17:49:20 +01:00
Lee Bousfield
c8d80a2920 ci: Fail on warnings (#9668)
* ci: Fail on warnings

* misc: Fix compiler warnings
2025-03-19 00:46:28 +01:00
Vaxry
03385fc07f seatmgr: avoid crash on null surfs 2025-03-18 19:43:05 +00:00
vaxerski
cca0f48b74 renderer: add an option to disable cm and auto-skip cm if not necessary
fixes #9641

adds render:cm_enabled default true
2025-03-18 11:30:08 +00:00
Kamikadze
60edb376f2 config/defaultConfig.hpp: windowrulev2 -> windowrule (#9663) 2025-03-18 13:13:03 +02:00
tachyglossues
6f74d8d7e9 example/hyprland.conf: windowrulev2 -> windowrule (#9662) 2025-03-18 12:24:43 +02:00
Vaxry
ec4bea7901 config: nuke windowrule v1 syntax 2025-03-18 01:37:00 +00:00
Honkazel
9171db1984 renderer: delete now redundant ifdefs (#9651)
Hyprland for now requires aquamarine =>0.8.0 anyway
2025-03-18 02:29:08 +01:00
Ikalco
5f60fc7d00 renderer: only commit hw cursor stuff if needed (#9654) 2025-03-17 22:06:41 +01:00
Lee Bousfield
c4f46473df monitor: Optimize direct scanout damage (#9653) 2025-03-17 22:05:44 +01:00
Lee Bousfield
011d7ccb91 internal: Fix compiler warnings (#9646) 2025-03-17 15:52:40 +01:00
Lee Bousfield
efc51eb7d1 managers: Use primary backend for cursor swapchain (#9645) 2025-03-17 15:51:18 +01:00
nyx
c2835b6b0f groupbar: remove recursive window recalc (#9561) 2025-03-17 15:50:49 +01:00
Mihai Fufezan
d5d7f69d1e flake.lock: update
aquamarine: bump to 0.8.0
hyprcursor: bump to 0.1.12
2025-03-17 14:50:35 +02:00
Ikalco
5cef2f44fe renderer: allow commits when buffer is unchanged but cursor changed (#9648) 2025-03-17 13:06:58 +01:00
Vaxry
22154fa272 opengl: simplify cm pipeline
fixes a few mistakes, and skips the CM shader in cpu instead of adding a costly branch

ref #9641
2025-03-16 21:50:20 +00:00
Mihai Fufezan
2ddd16ef28 CMake: install frag files (for real this time) 2025-03-16 19:35:37 +02:00
Mihai Fufezan
d7382aa8a1 CMake: install frag files 2025-03-16 18:27:27 +02:00
Mihai Fufezan
90306bdae6 Meson: include frags in globber 2025-03-16 16:30:50 +02:00
Vaxry
b1ab0f7539 splashes: update for 3ya 2025-03-16 03:03:37 +00:00
Tom Englund
bf5e4bf116 syncobj: dont crash compositor on protocol errors (#9627)
dont call a member on null pointer if client misbehaves.
as in the weak pointer being expired.
2025-03-15 19:57:52 +01:00
Blackilykat
4c471218c9 renderer: fix window offset for dragged windows (#9629) 2025-03-15 19:15:09 +01:00
phonetic112
e59680481d input: Fix clicking through groupbar tabs (#9606) 2025-03-15 01:22:39 +01:00
395 changed files with 20894 additions and 17563 deletions

View File

@@ -1,117 +1,15 @@
name: Bug Report name: Do not open issues, go to discussions please!
description: Something is not working right description: Do not open an issue
labels: ["bug"]
body: body:
- type: checkboxes - type: checkboxes
attributes: attributes:
label: Already reported ? * label: Please close this issue.
description: Before opening a new bug report, please take a moment to search through the current open issues. If the same bug is already reported, don't open new issue - instead go upvote/comment on an existing one. description: Users cannot open issues. I want my issue to be closed.
options: options:
- label: I have searched the existing open and closed issues. - label: Yes, I want this issue to be closed.
required: true required: true
- type: dropdown
id: type
attributes:
label: Regression?
description: |
Regression means that something used to work but no longer does.
**BEFORE CONTINUING**, please check if this bug is a regression or not, and if it is, we need you to bisect with the help of the wiki: https://wiki.hyprland.org/Crashes-and-Bugs/#bisecting-an-issue
multiple: true
options:
- "Definitely a regression - something broke after update (requires bisect)"
- "Probably not a regression / I don't remember it happening before"
- "Not a regression - it's bug regarding new feature"
- "Not a regression - it's an old bug"
- "I don't know, I started using Hyprland only recently"
validations:
required: true
- type: textarea - type: textarea
id: ver id: body
attributes: attributes:
label: System Info and Hyprland Version label: Issue body
description: |
Paste the output of `hyprctl systeminfo` here. If you can't
launch Hyprland, paste the output of `Hyprland --systeminfo`.
value: "<details>
<summary>System/Version info</summary>
```
<Paste the output of the command here, without removing any formatting around this>
```
</details>"
validations:
required: true
- type: textarea
id: desc
attributes:
label: Description
description: "What went wrong?"
validations:
required: true
- type: textarea
id: repro
attributes:
label: How to reproduce
description: "How can someone else reproduce the issue?"
placeholder: |
1. ...
2. ...
3. ...
validations:
required: true
- type: markdown
attributes:
value: |
## Additional info section
In the section below you will be asked to upload some files.
When including text files (such as logs or config), please **always ATTACH** them, and not paste them directly.
This is important to avoid clutter, spam, and make the issues more readable.
Thanks for your understanding.
# The main reason to disallow pasting directly or in a dropdown, is to not clutter
# the issue with unnecessary keywords, making the github issue search useless.
- type: checkboxes
attributes:
label: Attach not paste
options:
- label: I understand that all text files must be *attached*, and not pasted directly. If not respected, this issue will likely get closed as spam
required: true
- type: markdown
attributes:
value: >-
Please be sure to upload the following files below if they are relevant to the issue:
- Logs can be found in $XDG_RUNTIME_DIR/hypr (sort by date to grab the latest)
- Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland
- Hyprland config files - `hyprctl systeminfo -c > /tmp/hyprland_config_dump.txt` use this command to dump full configuration to a single file.
- type: checkboxes
attributes:
label: Checklist of files to include below
options:
- label: Hyprland config - `hyprctl systeminfo -c` (always include)
- label: Crash report (always include in case of crash)
- label: Video (always include in case of a visual bug)
- label: Logs (might contain useful info such as errors)
- type: textarea
id: logs
attributes:
label: Additional info & File uploads
description: |
Tip: You can attach files by clicking this area to highlight it and then dragging files in.

View File

@@ -1,19 +0,0 @@
name: Feature Request
description: I'd like to request additional functionality
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Before opening a new issue, take a moment to search through the current open ones.
---
- type: textarea
id: desc
attributes:
label: Description
description: "Describe your idea"
validations:
required: true

View File

@@ -20,6 +20,7 @@ runs:
clang \ clang \
cmake \ cmake \
git \ git \
glaze \
glm \ glm \
glslang \ glslang \
go \ go \
@@ -64,15 +65,6 @@ runs:
librsvg \ librsvg \
re2 re2
- name: Get glaze
shell: bash
run: |
git clone https://github.com/stephenberry/glaze.git
cd glaze
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
cmake --install build
- name: Get hyprwayland-scanner-git - name: Get hyprwayland-scanner-git
shell: bash shell: bash
run: | run: |

View File

@@ -21,7 +21,7 @@ jobs:
- name: Build Hyprland - name: Build Hyprland
run: | run: |
make all CFLAGS=-Werror CXXFLAGS=-Werror make all
- name: Compress and package artifacts - name: Compress and package artifacts
run: | run: |

101
.github/workflows/close-issues.yml vendored Normal file
View File

@@ -0,0 +1,101 @@
name: Close Unauthorized Issues
on:
workflow_dispatch:
issues:
types: [opened]
jobs:
close-unauthorized-issues:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
# XXX: This *could* be done in Bash by abusing GitHub's own tool to interact with its API
# but that's too much of a hack, and we'll be adding a layer of abstraction. github-script
# is a workflow that eases interaction with GitHub API in the workflow run context.
- name: "Close 'unauthorized' issues"
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const ALLOWED_USERS = ['vaxerski', 'fufexan', 'NotAShelf'];
const CLOSING_COMMENT = 'Users are no longer allowed to open issues themselves, please open a discussion instead.\n\nPlease see the [wiki](https://wiki.hyprland.org/Contributing-and-Debugging/Issue-Guidelines/) on why this is the case.\n\nWe are volunteers, and we need your cooperation to make the best software we can. Thank you for understanding! ❤️\n\n[Open a discussion here](https://github.com/hyprwm/Hyprland/discussions)';
async function closeUnauthorizedIssue(issueNumber, userName) {
if (ALLOWED_USERS.includes(userName)) {
console.log(`Issue #${issueNumber} - Created by authorized user ${userName}`);
return;
}
console.log(`Issue #${issueNumber} - Unauthorized, closing`);
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
state: 'closed',
state_reason: 'not_planned'
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: CLOSING_COMMENT
});
}
if (context.eventName === 'issues' && context.payload.action === 'opened') {
// Direct access to the issue that triggered the workflow
const issue = context.payload.issue;
// Skip if this is a PR
if (issue.pull_request) {
console.log(`Issue #${issue.number} - Skipping, this is a pull request`);
return;
}
// Process the single issue that triggered the workflow
await closeUnauthorizedIssue(issue.number, issue.user.login);
} else {
// For manual runs, we need to handle pagination
async function* fetchAllOpenIssues() {
let page = 1;
let hasNextPage = true;
while (hasNextPage) {
const response = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100,
page: page
});
if (response.data.length === 0) {
hasNextPage = false;
} else {
for (const issue of response.data) {
yield issue;
}
page++;
}
}
}
// Process issues one by one
for await (const issue of fetchAllOpenIssues()) {
try {
// Skip pull requests
if (issue.pull_request) {
console.log(`Issue #${issue.number} - Skipping, this is a pull request`);
continue;
}
await closeUnauthorizedIssue(issue.number, issue.user.login);
} catch (error) {
console.error(`Error processing issue #${issue.number}: ${error.message}`);
}
}
}

View File

@@ -1,28 +0,0 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/actions/stale
name: Mark stale issues and pull requests
on:
schedule:
- cron: "7 */4 * * *"
workflow_dispatch:
jobs:
stale:
if: github.repository == 'hyprwm/Hyprland'
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.STALEBOT_PAT }}
stale-issue-label: "stale"
stale-pr-label: "stale"
operations-per-run: 40
days-before-close: -1

2
.gitignore vendored
View File

@@ -28,6 +28,8 @@ protocols/*.c*
protocols/*.h* protocols/*.h*
.ccls-cache .ccls-cache
*.so *.so
src/render/shaders/*.inc
src/render/shaders/Shaders.hpp
hyprctl/hyprctl hyprctl/hyprctl

View File

@@ -25,6 +25,9 @@ message(STATUS "Gathering git info")
# Get git info hash and branch # Get git info hash and branch
execute_process(COMMAND ./scripts/generateVersion.sh execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# Make shader files includable
execute_process(COMMAND ./scripts/generateShaderIncludes.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
@@ -86,6 +89,7 @@ add_compile_options(
-Wno-missing-field-initializers -Wno-missing-field-initializers
-Wno-narrowing -Wno-narrowing
-Wno-pointer-arith -Wno-pointer-arith
-Wno-clobbered
-fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=)
set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE) set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
@@ -102,10 +106,10 @@ else()
endif() endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.8.0)
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) 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(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7)
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.1) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.7.0)
pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1)
string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION}) string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION})
@@ -129,7 +133,7 @@ pkg_check_modules(
xkbcommon xkbcommon
uuid uuid
wayland-server>=1.22.90 wayland-server>=1.22.90
wayland-protocols>=1.41 wayland-protocols>=1.43
cairo cairo
pango pango
pangocairo pangocairo
@@ -313,7 +317,7 @@ endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.2) pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4)
if(hyprland_protocols_dep_FOUND) if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
@@ -345,6 +349,7 @@ protocolnew("protocols" "wayland-drm" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-mapping-v1" true)
protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/tearing-control" "tearing-control-v1" false)
protocolnew("staging/fractional-scale" "fractional-scale-v1" false) protocolnew("staging/fractional-scale" "fractional-scale-v1" false)
@@ -379,6 +384,8 @@ protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
protocolnew("staging/security-context" "security-context-v1" false) protocolnew("staging/security-context" "security-context-v1" false)
protocolnew("staging/content-type" "content-type-v1" false) protocolnew("staging/content-type" "content-type-v1" false)
protocolnew("staging/color-management" "color-management-v1" false) protocolnew("staging/color-management" "color-management-v1" false)
protocolnew("staging/xdg-toplevel-tag" "xdg-toplevel-tag-v1" false)
protocolnew("staging/xdg-system-bell" "xdg-system-bell-v1" false)
protocolwayland() protocolwayland()
@@ -444,4 +451,7 @@ install(
DIRECTORY ${HEADERS_SRC} DIRECTORY ${HEADERS_SRC}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING FILES_MATCHING
PATTERN "*.h*") PATTERN "*.h"
PATTERN "*.hpp"
PATTERN "*.inc"
)

View File

@@ -52,7 +52,7 @@ installheaders:
cmake --build ./build --config Release --target generate-protocol-headers cmake --build ./build --config Release --target generate-protocol-headers
find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland find src -type f \( -name '*.hpp' -o -name '*.h' -o -name '*.inc' \) -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi

32
SECURITY.md Normal file
View File

@@ -0,0 +1,32 @@
# Hyprland Development Security Policy
If you have a bug that affects the security of your system, you may
want to privately disclose it instead of making it immediately public.
## Supported versions
_Only_ the most recent release on Github is supported. There are no LTS releases.
## What is not a security issue
Some examples of issues that should not be reported as security issues:
- An app can execute a command when ran outside of a sandbox
- An app can write / read hyprland sockets when ran outside of a sandbox
- Crashes
- Things that are protected via permissions when the permission system is disabled
## What is a security issue
Some examples of issues that should be reported as security issues:
- Sandboxed application executing arbitrary code via Hyprland
- Application being able to modify Hyprland's code on the fly
- Application being able to keylog / track user's activity beyond what the wayland protocols allow
## How to report security issues
Please report your security issues via either of these channels:
- Mail: `vaxry [at] vaxry [dot] net`
- Matrix: `@vaxry:matrix.vaxry.net`
- Discord: `@vaxry`

View File

@@ -1 +1 @@
0.47.0 0.49.0

View File

@@ -52,6 +52,23 @@ env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24 env = HYPRCURSOR_SIZE,24
###################
### PERMISSIONS ###
###################
# See https://wiki.hyprland.org/Configuring/Permissions/
# Please note permission changes here require a Hyprland restart and are not applied on-the-fly
# for security reasons
# ecosystem {
# enforce_permissions = 1
# }
# permission = /usr/(bin|local/bin)/grim, screencopy, allow
# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow
##################### #####################
### LOOK AND FEEL ### ### LOOK AND FEEL ###
##################### #####################
@@ -139,10 +156,10 @@ animations {
# uncomment all if you wish to use that. # uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1] # windowrule = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1] # windowrule = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1] # windowrule = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1] # windowrule = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
@@ -260,8 +277,8 @@ bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-
# Requires playerctl # Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next bindl = , XF86AudioNext, exec, playerctl next
@@ -276,14 +293,11 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules # See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule v1 # Example windowrule
# windowrule = float, ^(kitty)$ # windowrule = float,class:^(kitty)$,title:^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.* windowrule = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland # Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0

60
flake.lock generated
View File

@@ -16,11 +16,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741934125, "lastModified": 1745357003,
"narHash": "sha256-qwI47l3aKXRpDvmCKDbLV70iVfAqhpuKqT7qYHA4KJk=", "narHash": "sha256-jYwzQkv1r7HN/4qrAuKp+NR4YYNp2xDrOX5O9YVqkWo=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "aquamarine", "repo": "aquamarine",
"rev": "bea48d0bbe15fb3d758a8b6be865836c97056575", "rev": "a19cf76ee1a15c1c12083fa372747ce46387289f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -79,11 +79,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1738664950, "lastModified": 1745948457,
"narHash": "sha256-xIeGNM+iivwVHkv9tHwOqoUP5dDrtees34bbFKKMZYs=", "narHash": "sha256-lzTV10FJTCGNtMdgW5YAhCAqezeAzKOd/97HbQK8GTU=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "7c6d165e1eb9045a996551eb9f121b6d1b30adc3", "rev": "ac903e80b33ba6a88df83d02232483d99f327573",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -105,11 +105,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1739049071, "lastModified": 1745015490,
"narHash": "sha256-3+7TpXMrbsUXSwgr5VAKAnmkzMb6JO+Rvc9XRb5NMg4=", "narHash": "sha256-apEJ9zoSzmslhJ2vOKFcXTMZLUFYzh1ghfB6Rbw3Low=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprgraphics", "repo": "hyprgraphics",
"rev": "175c6b29b6ff82100539e7c4363a35a02c74dd73", "rev": "60754910946b4e2dc1377b967b7156cb989c5873",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -128,11 +128,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1738422629, "lastModified": 1743714874,
"narHash": "sha256-5v+bv75wJWvahyM2xcMTSNNxmV8a7hb01Eey5zYnBJw=", "narHash": "sha256-yt8F7NhMFCFHUHy/lNjH/pjZyIDFNk52Q4tivQ31WFo=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "755aef8dab49d0fc4663c715fa4ad221b2aedaed", "rev": "3a5c2bda1c1a4e55cc1330c782547695a93f05b2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -189,11 +189,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1739048983, "lastModified": 1745951494,
"narHash": "sha256-REhTcXq4qs3B3cCDtLlYDz0GZvmsBSh947Ub6pQWGTQ=", "narHash": "sha256-2dModE32doiyQMmd6EDAQeZnz+5LOs6KXyE0qX76WIg=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-qtutils", "repo": "hyprland-qtutils",
"rev": "3504a293c8f8db4127cb0f7cfc1a318ffb4316f8", "rev": "4be1d324faf8d6e82c2be9f8510d299984dfdd2e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -215,11 +215,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741191527, "lastModified": 1746655412,
"narHash": "sha256-kM+11Nch47Xwfgtw2EpRitJuORy4miwoMuRi5tyMBDY=", "narHash": "sha256-kVQ0bHVtX6baYxRWWIh4u3LNJZb9Zcm2xBeDPOGz5BY=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "72df3861f1197e41b078faa3e38eedd60e00018d", "rev": "557241780c179cf7ef224df392f8e67dab6cef83",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -238,11 +238,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741534688, "lastModified": 1746635225,
"narHash": "sha256-EV3945SnjOCuRVbGRghsWx/9D89FyshnSO1Q6/TuQ14=", "narHash": "sha256-W9G9bb0zRYDBRseHbVez0J8qVpD5QbizX67H/vsudhM=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprutils", "repo": "hyprutils",
"rev": "dd1f720cbc2dbb3c71167c9598045dd3261d27b3", "rev": "674ea57373f08b7609ce93baff131117a0dfe70d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -276,11 +276,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1741851582, "lastModified": 1746461020,
"narHash": "sha256-cPfs8qMccim2RBgtKGF+x9IBCduRvd/N5F4nYpU0TVE=", "narHash": "sha256-7+pG1I9jvxNlmln4YgnlW4o+w0TZX24k688mibiFDUE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "6607cf789e541e7873d40d3a8f7815ea92204f32", "rev": "3730d8a308f94996a9ba7c7138ede69c1b9ac4ae",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -299,11 +299,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741379162, "lastModified": 1746537231,
"narHash": "sha256-srpAbmJapkaqGRE3ytf3bj4XshspVR5964OX5LfjDWc=", "narHash": "sha256-Wb2xeSyOsCoTCTj7LOoD6cdKLEROyFAArnYoS+noCWo=",
"owner": "cachix", "owner": "cachix",
"repo": "git-hooks.nix", "repo": "git-hooks.nix",
"rev": "b5a62751225b2f62ff3147d0a334055ebadcd5cc", "rev": "fa466640195d38ec97cf0493d6d6882bc4d14969",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -365,11 +365,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1741934139, "lastModified": 1745871725,
"narHash": "sha256-ZhTcTH9FoeAtbPfWGrhkH7RjLJZ7GeF18nygLAMR+WE=", "narHash": "sha256-M24SNc2flblWGXFkGQfqSlEOzAGZnMc9QG3GH4K/KbE=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "150b0b6f52bb422a1b232a53698606fe0320dde0", "rev": "76bbf1a6b1378e4ab5230bad00ad04bc287c969e",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -23,7 +23,7 @@ _hyprctl () {
local words cword local words cword
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword _get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
declare -a literals=(resizeactive 2 changegroupactive -r moveintogroup forceallowsinput 4 ::= systeminfo all layouts setprop animationstyle switchxkblayout create denywindowfromgroup headless activebordercolor exec setcursor wayland focusurgentorlast workspacerules movecurrentworkspacetomonitor movetoworkspacesilent hyprpaper alpha inactivebordercolor movegroupwindow movecursortocorner movewindowpixel prev movewindow globalshortcuts clients dimaround setignoregrouplock splash execr monitors 0 forcenoborder -q animations 1 nomaxsize splitratio moveactive pass swapnext devices layers rounding lockactivegroup 5 moveworkspacetomonitor -f -i --quiet forcenodim pin 0 1 forceopaque forcenoshadow setfloating minsize alphaoverride sendshortcut workspaces cyclenext alterzorder togglegroup lockgroups bordersize dpms focuscurrentorlast -1 --batch notify remove instances 1 3 moveoutofgroup killactive 2 movetoworkspace movecursor configerrors closewindow swapwindow tagwindow forcerendererreload centerwindow auto focuswindow seterror nofocus alphafullscreen binds version -h togglespecialworkspace fullscreen windowdancecompat 0 keyword toggleopaque 3 --instance togglefloating renameworkspace alphafullscreenoverride activeworkspace x11 kill forceopaqueoverriden output global dispatch reload forcenoblur -j event --help disable -1 activewindow keepaspectratio dismissnotify focusmonitor movefocus plugin exit workspace fullscreenstate getoption alphainactiveoverride alphainactive decorations settiled config-only descriptions resizewindowpixel fakefullscreen rollinglog swapactiveworkspaces submap next movewindoworgroup cursorpos forcenoanims focusworkspaceoncurrentmonitor maxsize) declare -a literals=(resizeactive 2 changegroupactive -r moveintogroup forceallowsinput 4 ::= systeminfo all layouts setprop animationstyle switchxkblayout create denywindowfromgroup headless activebordercolor exec setcursor wayland focusurgentorlast workspacerules movecurrentworkspacetomonitor movetoworkspacesilent hyprpaper alpha inactivebordercolor movegroupwindow movecursortocorner movewindowpixel prev movewindow globalshortcuts clients dimaround setignoregrouplock splash execr monitors 0 forcenoborder -q animations 1 nomaxsize splitratio moveactive pass swapnext devices layers rounding lockactivegroup 5 moveworkspacetomonitor -f -i --quiet forcenodim pin 0 1 forceopaque forcenoshadow setfloating minsize alphaoverride sendshortcut workspaces cyclenext alterzorder togglegroup lockgroups bordersize dpms focuscurrentorlast -1 --batch notify remove instances 1 3 moveoutofgroup killactive 2 movetoworkspace movecursor configerrors closewindow swapwindow tagwindow forcerendererreload centerwindow auto focuswindow seterror nofocus alphafullscreen binds version -h togglespecialworkspace fullscreen windowdancecompat 0 keyword toggleopaque 3 --instance togglefloating renameworkspace alphafullscreenoverride activeworkspace x11 kill forceopaqueoverriden output global dispatch reload forcenoblur -j event --help disable -1 activewindow keepaspectratio dismissnotify focusmonitor movefocus plugin exit workspace fullscreenstate getoption alphainactiveoverride alphainactive decorations settiled config-only descriptions resizewindowpixel fakefullscreen rollinglog swapactiveworkspaces submap next movewindoworgroup cursorpos forcenoanims focusworkspaceoncurrentmonitor maxsize sendkeystate)
declare -A literal_transitions declare -A literal_transitions
literal_transitions[0]="([120]=14 [43]=2 [125]=21 [81]=2 [3]=21 [51]=2 [50]=2 [128]=2 [89]=2 [58]=21 [8]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [102]=21 [133]=7 [100]=2 [137]=2 [22]=2 [19]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [78]=21 [114]=2 [37]=2 [151]=2 [116]=2 [121]=13 [123]=21 [39]=11 [42]=21 [79]=15 [118]=12)" literal_transitions[0]="([120]=14 [43]=2 [125]=21 [81]=2 [3]=21 [51]=2 [50]=2 [128]=2 [89]=2 [58]=21 [8]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [102]=21 [133]=7 [100]=2 [137]=2 [22]=2 [19]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [78]=21 [114]=2 [37]=2 [151]=2 [116]=2 [121]=13 [123]=21 [39]=11 [42]=21 [79]=15 [118]=12)"
literal_transitions[1]="([81]=2 [51]=2 [50]=2 [128]=2 [8]=2 [89]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [133]=7 [100]=2 [22]=2 [19]=2 [137]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [114]=2 [37]=2 [151]=2 [116]=2 [39]=11 [118]=12 [121]=13 [120]=14 [79]=15 [43]=2)" literal_transitions[1]="([81]=2 [51]=2 [50]=2 [128]=2 [8]=2 [89]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [133]=7 [100]=2 [22]=2 [19]=2 [137]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [114]=2 [37]=2 [151]=2 [116]=2 [39]=11 [118]=12 [121]=13 [120]=14 [79]=15 [43]=2)"

View File

@@ -29,7 +29,7 @@ function _hyprctl
set COMP_CWORD (count $COMP_WORDS) set COMP_CWORD (count $COMP_WORDS)
end end
set literals "resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" set literals "resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" "sendkeystate"
set descriptions set descriptions
set descriptions[1] "Resize the active window" set descriptions[1] "Resize the active window"

View File

@@ -106,6 +106,7 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (execr) "Execute a raw shell command" | (execr) "Execute a raw shell command"
| (pass) "Pass the key to a specified window" | (pass) "Pass the key to a specified window"
| (sendshortcut) "On shortcut X sends shortcut Y to a specified window" | (sendshortcut) "On shortcut X sends shortcut Y to a specified window"
| (sendkeystate) "Send a key with specific state (down/repeat/up) to a specified window (window must keep focus for events to continue)"
| (killactive) "Close the active window" | (killactive) "Close the active window"
| (closewindow) "Close a specified window" | (closewindow) "Close a specified window"
| (workspace) "Change the workspace" | (workspace) "Change the workspace"

View File

@@ -17,7 +17,7 @@ _hyprctl_cmd_0 () {
} }
_hyprctl () { _hyprctl () {
local -a literals=("resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize") local -a literals=("resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" "sendkeystate")
local -A descriptions local -A descriptions
descriptions[1]="Resize the active window" descriptions[1]="Resize the active window"

View File

@@ -9,11 +9,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4) pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.7.0)
find_package(glaze QUIET) find_package(glaze QUIET)
if (NOT glaze_FOUND) if (NOT glaze_FOUND)
set(GLAZE_VERSION v4.2.3) set(GLAZE_VERSION v5.1.1)
message(STATUS "glaze dependency not found, retrieving ${GLAZE_VERSION} with FetchContent") message(STATUS "glaze dependency not found, retrieving ${GLAZE_VERSION} with FetchContent")
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(

View File

@@ -1,22 +1,41 @@
#include "DataState.hpp" #include "DataState.hpp"
#include <sys/stat.h>
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <print> #include <print>
#include <sstream>
#include <fstream> #include <fstream>
#include "PluginManager.hpp" #include "PluginManager.hpp"
#include "../helpers/Die.hpp"
#include "../helpers/Sys.hpp"
#include "../helpers/StringUtils.hpp"
std::filesystem::path DataState::getDataStatePath() { static std::string getTempRoot() {
const auto HOME = getenv("HOME"); static auto ENV = getenv("XDG_RUNTIME_DIR");
if (!HOME) { if (!ENV) {
std::println(stderr, "DataState: no $HOME"); std::cerr << "\nERROR: XDG_RUNTIME_DIR not set!\n";
throw std::runtime_error("no $HOME"); exit(1);
return "";
} }
const auto XDG_DATA_HOME = getenv("XDG_DATA_HOME"); const auto STR = ENV + std::string{"/hyprpm/"};
if (XDG_DATA_HOME) return STR;
return std::filesystem::path{XDG_DATA_HOME} / "hyprpm"; }
return std::filesystem::path{HOME} / ".local/share/hyprpm";
// write the state to a file
static bool writeState(const std::string& str, const std::string& to) {
// create temp file in a safe temp root
std::ofstream of(getTempRoot() + ".temp-state", std::ios::trunc);
if (!of.good())
return false;
of << str;
of.close();
return NSys::root::install(getTempRoot() + ".temp-state", to, "644");
}
std::filesystem::path DataState::getDataStatePath() {
return std::filesystem::path("/var/cache/hyprpm/" + g_pPluginManager->m_szUsername);
} }
std::string DataState::getHeadersPath() { std::string DataState::getHeadersPath() {
@@ -41,21 +60,32 @@ std::vector<std::filesystem::path> DataState::getPluginStates() {
} }
void DataState::ensureStateStoreExists() { void DataState::ensureStateStoreExists() {
const auto PATH = getDataStatePath(); std::error_code ec;
if (!std::filesystem::exists(getHeadersPath(), ec) || ec) {
if (!std::filesystem::exists(PATH)) std::println("{}", infoString("The hyprpm state store doesn't exist. Creating now..."));
std::filesystem::create_directories(PATH); if (!std::filesystem::exists("/var/cache/hyprpm/", ec) || ec) {
if (!NSys::root::createDirectory("/var/cache/hyprpm", "755"))
if (!std::filesystem::exists(getHeadersPath())) Debug::die("ensureStateStoreExists: Failed to run a superuser cmd");
std::filesystem::create_directories(getHeadersPath()); }
if (!std::filesystem::exists(getDataStatePath(), ec) || ec) {
if (!NSys::root::createDirectory(getDataStatePath().string(), "755"))
Debug::die("ensureStateStoreExists: Failed to run a superuser cmd");
}
if (!NSys::root::createDirectory(getHeadersPath(), "755"))
Debug::die("ensureStateStoreExists: Failed to run a superuser cmd");
}
} }
void DataState::addNewPluginRepo(const SPluginRepository& repo) { void DataState::addNewPluginRepo(const SPluginRepository& repo) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath() / repo.name; const auto PATH = getDataStatePath() / repo.name;
std::filesystem::create_directories(PATH); std::error_code ec;
if (!std::filesystem::exists(PATH, ec) || ec) {
if (!NSys::root::createDirectory(PATH.string(), "755"))
Debug::die("addNewPluginRepo: failed to create cache dir");
}
// clang-format off // clang-format off
auto DATA = toml::table{ auto DATA = toml::table{
{"repository", toml::table{ {"repository", toml::table{
@@ -68,9 +98,11 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
for (auto const& p : repo.plugins) { for (auto const& p : repo.plugins) {
const auto filename = p.name + ".so"; const auto filename = p.name + ".so";
// copy .so to the good place // copy .so to the good place and chmod 755
if (std::filesystem::exists(p.filename)) if (std::filesystem::exists(p.filename)) {
std::filesystem::copy_file(p.filename, PATH / filename); if (!NSys::root::install(p.filename, (PATH / filename).string(), "0755"))
Debug::die("addNewPluginRepo: failed to install so file");
}
DATA.emplace(p.name, toml::table{ DATA.emplace(p.name, toml::table{
{"filename", filename}, {"filename", filename},
@@ -80,16 +112,16 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
} }
// clang-format on // clang-format on
std::ofstream ofs(PATH / "state.toml", std::ios::trunc); std::stringstream ss;
ofs << DATA; ss << DATA;
ofs.close();
if (!writeState(ss.str(), (PATH / "state.toml").string()))
Debug::die("{}", failureString("Failed to write plugin state"));
} }
bool DataState::pluginRepoExists(const std::string& urlOrName) { bool DataState::pluginRepoExists(const std::string& urlOrName) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
const auto NAME = STATE["repository"]["name"].value_or(""); const auto NAME = STATE["repository"]["name"].value_or("");
@@ -105,8 +137,6 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
void DataState::removePluginRepo(const std::string& urlOrName) { void DataState::removePluginRepo(const std::string& urlOrName) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
const auto NAME = STATE["repository"]["name"].value_or(""); const auto NAME = STATE["repository"]["name"].value_or("");
@@ -122,7 +152,14 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false); g_pPluginManager->loadUnloadPlugin(std::filesystem::absolute(file.path()), false);
} }
std::filesystem::remove_all(stateFile.parent_path()); const auto PATH = stateFile.parent_path().string();
if (!PATH.starts_with("/var/cache/hyprpm") || PATH.contains('\''))
return; // WTF?
// scary!
if (!NSys::root::removeRecursive(PATH))
Debug::die("removePluginRepo: failed to remove dir");
return; return;
} }
} }
@@ -131,9 +168,13 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
void DataState::updateGlobalState(const SGlobalState& state) { void DataState::updateGlobalState(const SGlobalState& state) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath(); const auto PATH = getDataStatePath();
std::filesystem::create_directories(PATH); std::error_code ec;
if (!std::filesystem::exists(PATH, ec) || ec) {
if (!NSys::root::createDirectory(PATH.string(), "755"))
Debug::die("updateGlobalState: failed to create dir");
}
// clang-format off // clang-format off
auto DATA = toml::table{ auto DATA = toml::table{
{"state", toml::table{ {"state", toml::table{
@@ -143,17 +184,20 @@ void DataState::updateGlobalState(const SGlobalState& state) {
}; };
// clang-format on // clang-format on
std::ofstream ofs(PATH / "state.toml", std::ios::trunc); std::stringstream ss;
ofs << DATA; ss << DATA;
ofs.close();
if (!writeState(ss.str(), (PATH / "state.toml").string()))
Debug::die("{}", failureString("Failed to write plugin state"));
} }
SGlobalState DataState::getGlobalState() { SGlobalState DataState::getGlobalState() {
ensureStateStoreExists(); ensureStateStoreExists();
const auto stateFile = getDataStatePath() / "state.toml"; const auto stateFile = getDataStatePath() / "state.toml";
if (!std::filesystem::exists(stateFile)) std::error_code ec;
if (!std::filesystem::exists(stateFile, ec) || ec)
return SGlobalState{}; return SGlobalState{};
auto DATA = toml::parse_file(stateFile.c_str()); auto DATA = toml::parse_file(stateFile.c_str());
@@ -168,8 +212,6 @@ SGlobalState DataState::getGlobalState() {
std::vector<SPluginRepository> DataState::getAllRepositories() { std::vector<SPluginRepository> DataState::getAllRepositories() {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
std::vector<SPluginRepository> repos; std::vector<SPluginRepository> repos;
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
@@ -205,8 +247,6 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
bool DataState::setPluginEnabled(const std::string& name, bool enabled) { bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
ensureStateStoreExists(); ensureStateStoreExists();
const auto PATH = getDataStatePath();
for (const auto& stateFile : getPluginStates()) { for (const auto& stateFile : getPluginStates()) {
const auto STATE = toml::parse_file(stateFile.c_str()); const auto STATE = toml::parse_file(stateFile.c_str());
for (const auto& [key, val] : STATE) { for (const auto& [key, val] : STATE) {
@@ -224,9 +264,11 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
auto modifiedState = STATE; auto modifiedState = STATE;
(*modifiedState[key].as_table()).insert_or_assign("enabled", enabled); (*modifiedState[key].as_table()).insert_or_assign("enabled", enabled);
std::ofstream state(stateFile, std::ios::trunc); std::stringstream ss;
state << modifiedState; ss << modifiedState;
state.close();
if (!writeState(ss.str(), stateFile.string()))
Debug::die("{}", failureString("Failed to write plugin state"));
return true; return true;
} }
@@ -234,3 +276,18 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
return false; return false;
} }
void DataState::purgeAllCache() {
std::error_code ec;
if (!std::filesystem::exists(getDataStatePath()) && !ec) {
std::println("{}", infoString("Nothing to do"));
return;
}
const auto PATH = getDataStatePath().string();
if (PATH.contains('\''))
return;
// scary!
if (!NSys::root::removeRecursive(PATH))
Debug::die("Failed to run a superuser cmd");
}

View File

@@ -18,6 +18,7 @@ namespace DataState {
void removePluginRepo(const std::string& urlOrName); void removePluginRepo(const std::string& urlOrName);
bool pluginRepoExists(const std::string& urlOrName); bool pluginRepoExists(const std::string& urlOrName);
void updateGlobalState(const SGlobalState& state); void updateGlobalState(const SGlobalState& state);
void purgeAllCache();
SGlobalState getGlobalState(); SGlobalState getGlobalState();
bool setPluginEnabled(const std::string& name, bool enabled); bool setPluginEnabled(const std::string& name, bool enabled);
std::vector<SPluginRepository> getAllRepositories(); std::vector<SPluginRepository> getAllRepositories();

View File

@@ -0,0 +1,85 @@
#include "HyprlandSocket.hpp"
#include <pwd.h>
#include <sys/socket.h>
#include "../helpers/StringUtils.hpp"
#include <print>
#include <sys/un.h>
#include <unistd.h>
static int getUID() {
const auto UID = getuid();
const auto PWUID = getpwuid(UID);
return PWUID ? PWUID->pw_uid : UID;
}
static std::string getRuntimeDir() {
const auto XDG = getenv("XDG_RUNTIME_DIR");
if (!XDG) {
const std::string USERID = std::to_string(getUID());
return "/run/user/" + USERID + "/hypr";
}
return std::string{XDG} + "/hypr";
}
std::string NHyprlandSocket::send(const std::string& cmd) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
if (SERVERSOCKET < 0) {
std::println("{}", failureString("Couldn't open a socket (1)"));
return "";
}
const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!HIS) {
std::println("{}", failureString("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?) (3)"));
return "";
}
sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX;
std::string socketPath = getRuntimeDir() + "/" + HIS + "/.socket.sock";
strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
std::println("{}", failureString("Couldn't connect to " + socketPath + ". (4)"));
return "";
}
auto sizeWritten = write(SERVERSOCKET, cmd.c_str(), cmd.length());
if (sizeWritten < 0) {
std::println("{}", failureString("Couldn't write (5)"));
return "";
}
std::string reply = "";
constexpr size_t BUFFER_SIZE = 8192;
char buffer[BUFFER_SIZE] = {0};
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
if (sizeWritten < 0) {
std::println("{}", failureString("Couldn't read (6)"));
return "";
}
reply += std::string(buffer, sizeWritten);
while (sizeWritten == BUFFER_SIZE) {
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
if (sizeWritten < 0) {
std::println("{}", failureString("Couldn't read (7)"));
return "";
}
reply += std::string(buffer, sizeWritten);
}
close(SERVERSOCKET);
return reply;
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include <string>
namespace NHyprlandSocket {
std::string send(const std::string& cmd);
};

View File

@@ -1,6 +1,12 @@
#include "Manifest.hpp" #include "Manifest.hpp"
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
#include <iostream> #include <algorithm>
// Alphanumerics and -_ allowed for plugin names. No magic names.
// [A-Za-z0-9\-_]*
static bool validManifestName(const std::string_view& n) {
return std::ranges::all_of(n, [](const char& c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '-' || c == '_' || c == '=' || (c >= '0' && c <= '9'); });
}
CManifest::CManifest(const eManifestType type, const std::string& path) { CManifest::CManifest(const eManifestType type, const std::string& path) {
auto manifest = toml::parse_file(path); auto manifest = toml::parse_file(path);
@@ -11,11 +17,17 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
continue; continue;
CManifest::SManifestPlugin plugin; CManifest::SManifestPlugin plugin;
if (!validManifestName(key.str())) {
m_good = false;
return;
}
plugin.name = key; plugin.name = key;
m_vPlugins.push_back(plugin); m_plugins.push_back(plugin);
} }
for (auto& plugin : m_vPlugins) { for (auto& plugin : m_plugins) {
plugin.description = manifest[plugin.name]["description"].value_or("?"); plugin.description = manifest[plugin.name]["description"].value_or("?");
plugin.version = manifest[plugin.name]["version"].value_or("?"); plugin.version = manifest[plugin.name]["version"].value_or("?");
plugin.output = manifest[plugin.name]["build"]["output"].value_or("?"); plugin.output = manifest[plugin.name]["build"]["output"].value_or("?");
@@ -37,21 +49,21 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
} }
if (plugin.output.empty() || plugin.buildSteps.empty()) { if (plugin.output.empty() || plugin.buildSteps.empty()) {
m_bGood = false; m_good = false;
return; return;
} }
} }
} else if (type == MANIFEST_HYPRPM) { } else if (type == MANIFEST_HYPRPM) {
m_sRepository.name = manifest["repository"]["name"].value_or(""); m_repository.name = manifest["repository"]["name"].value_or("");
auto authors = manifest["repository"]["authors"].as_array(); auto authors = manifest["repository"]["authors"].as_array();
if (authors) { if (authors) {
for (auto&& a : *authors) { for (auto&& a : *authors) {
m_sRepository.authors.push_back(a.as_string()->value_or("?")); m_repository.authors.push_back(a.as_string()->value_or("?"));
} }
} else { } else {
auto author = manifest["repository"]["author"].value_or(""); auto author = manifest["repository"]["author"].value_or("");
if (!std::string{author}.empty()) if (!std::string{author}.empty())
m_sRepository.authors.push_back(author); m_repository.authors.push_back(author);
} }
auto pins = manifest["repository"]["commit_pins"].as_array(); auto pins = manifest["repository"]["commit_pins"].as_array();
@@ -59,7 +71,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
for (auto&& pin : *pins) { for (auto&& pin : *pins) {
auto pinArr = pin.as_array(); auto pinArr = pin.as_array();
if (pinArr && pinArr->get(1)) if (pinArr && pinArr->get(1))
m_sRepository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get())); m_repository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get()));
} }
} }
@@ -68,11 +80,17 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
continue; continue;
CManifest::SManifestPlugin plugin; CManifest::SManifestPlugin plugin;
if (!validManifestName(key.str())) {
m_good = false;
return;
}
plugin.name = key; plugin.name = key;
m_vPlugins.push_back(plugin); m_plugins.push_back(plugin);
} }
for (auto& plugin : m_vPlugins) { for (auto& plugin : m_plugins) {
plugin.description = manifest[plugin.name]["description"].value_or("?"); plugin.description = manifest[plugin.name]["description"].value_or("?");
plugin.output = manifest[plugin.name]["output"].value_or("?"); plugin.output = manifest[plugin.name]["output"].value_or("?");
plugin.since = manifest[plugin.name]["since_hyprland"].value_or(0); plugin.since = manifest[plugin.name]["since_hyprland"].value_or(0);
@@ -94,12 +112,12 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
} }
if (plugin.output.empty() || plugin.buildSteps.empty()) { if (plugin.output.empty() || plugin.buildSteps.empty()) {
m_bGood = false; m_good = false;
return; return;
} }
} }
} else { } else {
// ??? // ???
m_bGood = false; m_good = false;
} }
} }

View File

@@ -27,8 +27,8 @@ class CManifest {
std::string name; std::string name;
std::vector<std::string> authors; std::vector<std::string> authors;
std::vector<std::pair<std::string, std::string>> commitPins; std::vector<std::pair<std::string, std::string>> commitPins;
} m_sRepository; } m_repository;
std::vector<SManifestPlugin> m_vPlugins; std::vector<SManifestPlugin> m_plugins;
bool m_bGood = true; bool m_good = true;
}; };

View File

@@ -4,6 +4,9 @@
#include "../progress/CProgressBar.hpp" #include "../progress/CProgressBar.hpp"
#include "Manifest.hpp" #include "Manifest.hpp"
#include "DataState.hpp" #include "DataState.hpp"
#include "HyprlandSocket.hpp"
#include "../helpers/Sys.hpp"
#include "../helpers/Die.hpp"
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
@@ -49,6 +52,13 @@ static std::string getTempRoot() {
return STR; return STR;
} }
CPluginManager::CPluginManager() {
if (NSys::isSuperuser())
Debug::die("Don't run hyprpm as a superuser.");
m_szUsername = getpwuid(NSys::getUID())->pw_name;
}
SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) { SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
static bool onceRunning = false; static bool onceRunning = false;
static bool onceInstalled = false; static bool onceInstalled = false;
@@ -66,7 +76,7 @@ SHyprlandVersion CPluginManager::getHyprlandVersion(bool running) {
else else
onceInstalled = true; onceInstalled = true;
const auto HLVERCALL = running ? execAndGet("hyprctl version") : execAndGet("Hyprland --version"); const auto HLVERCALL = running ? NHyprlandSocket::send("/version") : execAndGet("Hyprland --version");
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("{} version returned: {}", running ? "running" : "installed", HLVERCALL)); std::println("{}", verboseString("{} version returned: {}", running ? "running" : "installed", HLVERCALL));
@@ -129,7 +139,8 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) { if (!hasDeps()) {
std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config")); std::println(stderr, "\n{}",
failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config, git, g++, gcc"));
return false; return false;
} }
@@ -225,14 +236,14 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
return false; return false;
} }
if (!pManifest->m_bGood) { if (!pManifest->m_good) {
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest"));
return false; return false;
} }
progress.m_iSteps = 2; progress.m_iSteps = 2;
progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:")); progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_plugins.size()) + " plugins:"));
for (auto const& pl : pManifest->m_vPlugins) { for (auto const& pl : pManifest->m_plugins) {
std::string message = "" + pl.name + " by "; std::string message = "" + pl.name + " by ";
for (auto const& a : pl.authors) { for (auto const& a : pl.authors) {
message += a + ", "; message += a + ", ";
@@ -245,12 +256,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.printMessageAbove(message); progress.printMessageAbove(message);
} }
if (!pManifest->m_sRepository.commitPins.empty()) { if (!pManifest->m_repository.commitPins.empty()) {
// check commit pins // check commit pins
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_repository.commitPins.size()));
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { for (auto const& [hl, plugin] : pManifest->m_repository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
@@ -273,6 +284,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
if (HEADERSSTATUS != HEADERS_OK) { if (HEADERSSTATUS != HEADERS_OK) {
std::println("\n{}", headerError(HEADERSSTATUS)); std::println("\n{}", headerError(HEADERSSTATUS));
std::println("\n{}", infoString("if the problem persists, try running hyprpm purge-cache."));
return false; return false;
} }
@@ -281,7 +293,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.m_szCurrentMessage = "Building plugin(s)"; progress.m_szCurrentMessage = "Building plugin(s)";
progress.print(); progress.print();
for (auto& p : pManifest->m_vPlugins) { for (auto& p : pManifest->m_plugins) {
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) { if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) {
@@ -324,11 +336,11 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::string repohash = execAndGet("cd " + m_szWorkingPluginDirectory + " && git rev-parse HEAD"); std::string repohash = execAndGet("cd " + m_szWorkingPluginDirectory + " && git rev-parse HEAD");
if (repohash.length() > 0) if (repohash.length() > 0)
repohash.pop_back(); repohash.pop_back();
repo.name = pManifest->m_sRepository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_sRepository.name; repo.name = pManifest->m_repository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_repository.name;
repo.url = url; repo.url = url;
repo.rev = rev; repo.rev = rev;
repo.hash = repohash; repo.hash = repohash;
for (auto const& p : pManifest->m_vPlugins) { for (auto const& p : pManifest->m_plugins) {
repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed}); repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed});
} }
DataState::addNewPluginRepo(repo); DataState::addNewPluginRepo(repo);
@@ -435,7 +447,7 @@ bool CPluginManager::updateHeaders(bool force) {
const auto HLVER = getHyprlandVersion(false); const auto HLVER = getHyprlandVersion(false);
if (!hasDeps()) { if (!hasDeps()) {
std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config")); std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config, git, g++, gcc"));
return false; return false;
} }
@@ -548,13 +560,21 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";
progress.print(); progress.print();
const std::string& cmd = std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile", DataState::getHeadersPath(), WORKINGDIR);
std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(verboseString("installation will run: {}", cmd)); progress.printMessageAbove(verboseString("prepare install will run: {}", cmd));
ret = execAndGet(cmd); ret = execAndGet(cmd);
cmd = std::format("make -C '{}' installheaders && chmod -R 644 '{}' && find '{}' -type d -exec chmod o+x {{}} \\;", WORKINGDIR, DataState::getHeadersPath(),
DataState::getHeadersPath());
if (m_bVerbose)
progress.printMessageAbove(verboseString("install will run as sudo: {}", cmd));
// WORKINGDIR and headersPath should not contain anything unsafe. Usernames can't contain cmd exec parts.
ret = NSys::root::runAsSuperuserUnsafe(cmd);
if (m_bVerbose) if (m_bVerbose)
std::println("{}", verboseString("installer returned: {}", ret)); std::println("{}", verboseString("installer returned: {}", ret));
@@ -568,9 +588,14 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Done!"; progress.m_szCurrentMessage = "Done!";
progress.print(); progress.print();
auto GLOBALSTATE = DataState::getGlobalState();
GLOBALSTATE.headersHashCompiled = HLVER.hash;
DataState::updateGlobalState(GLOBALSTATE);
std::print("\n"); std::print("\n");
} else { } else {
progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID))); progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID)));
progress.printMessageAbove(infoString("if the problem persists, try running hyprpm purge-cache."));
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Failed"; progress.m_szCurrentMessage = "Failed";
progress.print(); progress.print();
@@ -677,17 +702,17 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
continue; continue;
} }
if (!pManifest->m_bGood) { if (!pManifest->m_good) {
std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); std::println(stderr, "\n{}", failureString("The provided plugin repository has a bad manifest"));
continue; continue;
} }
if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) { if (repo.rev.empty() && !pManifest->m_repository.commitPins.empty()) {
// check commit pins unless a revision is specified // check commit pins unless a revision is specified
progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_repository.commitPins.size()));
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { for (auto const& [hl, plugin] : pManifest->m_repository.commitPins) {
if (hl != HLVER.hash) if (hl != HLVER.hash)
continue; continue;
@@ -697,7 +722,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
} }
} }
for (auto& p : pManifest->m_vPlugins) { for (auto& p : pManifest->m_plugins) {
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) { if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) {
@@ -739,7 +764,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (repohash.length() > 0) if (repohash.length() > 0)
repohash.pop_back(); repohash.pop_back();
newrepo.hash = repohash; newrepo.hash = repohash;
for (auto const& p : pManifest->m_vPlugins) { for (auto const& p : pManifest->m_plugins) {
const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; }); const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; });
newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false}); newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false});
} }
@@ -796,9 +821,9 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState(bool forceReload)
} }
const auto HYPRPMPATH = DataState::getDataStatePath(); const auto HYPRPMPATH = DataState::getDataStatePath();
const auto json = glz::read_json<glz::json_t::array_t>(execAndGet("hyprctl plugins list -j")); const auto json = glz::read_json<glz::json_t::array_t>(NHyprlandSocket::send("j/plugins list"));
if (!json) { if (!json) {
std::println(stderr, "PluginManager: couldn't parse hyprctl output"); std::println(stderr, "PluginManager: couldn't parse plugin list output");
return LOADSTATE_FAIL; return LOADSTATE_FAIL;
} }
@@ -882,14 +907,15 @@ bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
auto HLVER = getHyprlandVersion(true); auto HLVER = getHyprlandVersion(true);
if (state.headersHashCompiled != HLVER.hash) { if (state.headersHashCompiled != HLVER.hash) {
std::println("{}", infoString("Running Hyprland version differs from plugin state, please restart Hyprland.")); if (load)
std::println("{}", infoString("Running Hyprland version ({}) differs from plugin state ({}), please restart Hyprland.", HLVER.hash, state.headersHashCompiled));
return false; return false;
} }
if (load) if (load)
execAndGet("hyprctl plugin load " + path); NHyprlandSocket::send("/plugin load " + path);
else else
execAndGet("hyprctl plugin unload " + path); NHyprlandSocket::send("/plugin unload " + path);
return true; return true;
} }
@@ -914,7 +940,7 @@ void CPluginManager::listAllPlugins() {
} }
void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message) { void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message) {
execAndGet("hyprctl notify " + std::to_string((int)icon) + " " + std::to_string(durationMs) + " " + std::to_string(color) + " " + message); NHyprlandSocket::send("/notify " + std::to_string((int)icon) + " " + std::to_string(durationMs) + " " + std::to_string(color) + " " + message);
} }
std::string CPluginManager::headerError(const eHeadersErrors err) { std::string CPluginManager::headerError(const eHeadersErrors err) {
@@ -947,7 +973,7 @@ std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {
} }
bool CPluginManager::hasDeps() { bool CPluginManager::hasDeps() {
std::vector<std::string> deps = {"meson", "cpio", "cmake", "pkg-config"}; std::vector<std::string> deps = {"meson", "cpio", "cmake", "pkg-config", "g++", "gcc", "git"};
for (auto const& d : deps) { for (auto const& d : deps) {
if (!execAndGet("command -v " + d).contains("/")) if (!execAndGet("command -v " + d).contains("/"))
return false; return false;

View File

@@ -40,6 +40,8 @@ struct SHyprlandVersion {
class CPluginManager { class CPluginManager {
public: public:
CPluginManager();
bool addNewPluginRepo(const std::string& url, const std::string& rev); bool addNewPluginRepo(const std::string& url, const std::string& rev);
bool removePluginRepo(const std::string& urlOrName); bool removePluginRepo(const std::string& urlOrName);
@@ -62,7 +64,7 @@ class CPluginManager {
bool m_bVerbose = false; bool m_bVerbose = false;
bool m_bNoShallow = false; bool m_bNoShallow = false;
std::string m_szCustomHlUrl; std::string m_szCustomHlUrl, m_szUsername;
// will delete recursively if exists!! // will delete recursively if exists!!
bool createSafeDirectory(const std::string& path); bool createSafeDirectory(const std::string& path);

View File

@@ -0,0 +1,15 @@
#pragma once
#include <format>
#include <iostream>
// NOLINTNEXTLINE
namespace Debug {
template <typename... Args>
void die(std::format_string<Args...> fmt, Args&&... args) {
const std::string logMsg = std::vformat(fmt.get(), std::make_format_args(args...));
std::cout << "\n[ERR] " << logMsg << "\n";
exit(1);
}
};

167
hyprpm/src/helpers/Sys.cpp Normal file
View File

@@ -0,0 +1,167 @@
#include "Sys.hpp"
#include "Die.hpp"
#include "StringUtils.hpp"
#include <pwd.h>
#include <unistd.h>
#include <print>
#include <filesystem>
#include <algorithm>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/string/VarList.hpp>
using namespace Hyprutils::OS;
using namespace Hyprutils::String;
inline constexpr std::array<std::string_view, 3> SUPERUSER_BINARIES = {
"sudo",
"doas",
"run0",
};
static std::string validSubinsAsStr() {
std::ostringstream oss;
auto it = SUPERUSER_BINARIES.begin();
if (it != SUPERUSER_BINARIES.end()) {
oss << *it++;
for (; it != SUPERUSER_BINARIES.end(); ++it)
oss << ", " << *it;
}
return oss.str();
}
static bool executableExistsInPath(const std::string& exe) {
const char* PATHENV = std::getenv("PATH");
if (!PATHENV)
return false;
CVarList paths(PATHENV, 0, ':', true);
std::error_code ec;
for (const auto& PATH : paths) {
std::filesystem::path candidate = std::filesystem::path(PATH) / exe;
if (!std::filesystem::exists(candidate, ec) || ec)
continue;
if (!std::filesystem::is_regular_file(candidate, ec) || ec)
continue;
auto perms = std::filesystem::status(candidate, ec).permissions();
if (ec)
continue;
if ((perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none)
return true;
}
return false;
}
static std::string subin() {
static std::string bin;
static bool once = true;
if (!once)
return bin;
for (const auto& BIN : SUPERUSER_BINARIES) {
if (!executableExistsInPath(std::string{BIN}))
continue;
bin = BIN;
break;
}
once = false;
if (bin.empty())
Debug::die("{}", failureString("No valid superuser binary present. Supported: {}", validSubinsAsStr()));
return bin;
}
static bool verifyStringValid(const std::string& s) {
return std::ranges::none_of(s, [](const char& c) { return c == '`' || c == '$' || c == '(' || c == ')' || c == '\'' || c == '"'; });
}
int NSys::getUID() {
const auto UID = getuid();
const auto PWUID = getpwuid(UID);
return PWUID ? PWUID->pw_uid : UID;
}
int NSys::getEUID() {
const auto UID = geteuid();
const auto PWUID = getpwuid(UID);
return PWUID ? PWUID->pw_uid : UID;
}
bool NSys::isSuperuser() {
return getuid() != geteuid() || geteuid() == 0;
}
void NSys::root::cacheSudo() {
// "caches" the sudo so that the prompt later doesn't pop up in a weird spot
// sudo will not ask us again for a moment
CProcess proc(subin(), {"echo", "hyprland"});
proc.runSync();
}
void NSys::root::dropSudo() {
if (subin() != "sudo") {
std::println("{}", infoString("Don't know how to drop timestamp for '{}', ignoring.", subin()));
return;
}
CProcess proc(subin(), {"-k"});
proc.runSync();
}
bool NSys::root::createDirectory(const std::string& path, const std::string& mode) {
if (!verifyStringValid(path))
return false;
if (!std::ranges::all_of(mode, [](const char& c) { return c >= '0' && c <= '9'; }))
return false;
CProcess proc(subin(), {"mkdir", "-p", "-m", mode, path});
return proc.runSync() && proc.exitCode() == 0;
}
bool NSys::root::removeRecursive(const std::string& path) {
if (!verifyStringValid(path))
return false;
std::error_code ec;
const std::string PATH_ABSOLUTE = std::filesystem::canonical(path, ec);
if (ec)
return false;
if (!PATH_ABSOLUTE.starts_with("/var/cache/hyprpm"))
return false;
CProcess proc(subin(), {"rm", "-fr", PATH_ABSOLUTE});
return proc.runSync() && proc.exitCode() == 0;
}
bool NSys::root::install(const std::string& what, const std::string& where, const std::string& mode) {
if (!verifyStringValid(what) || !verifyStringValid(where))
return false;
if (!std::ranges::all_of(mode, [](const char& c) { return c >= '0' && c <= '9'; }))
return false;
CProcess proc(subin(), {"install", "-m" + mode, "-o", "root", "-g", "root", what, where});
return proc.runSync() && proc.exitCode() == 0;
}
std::string NSys::root::runAsSuperuserUnsafe(const std::string& cmd) {
CProcess proc(subin(), {"/bin/sh", "-c", cmd});
if (!proc.runSync())
return "";
return proc.stdOut();
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include <string>
namespace NSys {
bool isSuperuser();
int getUID();
int getEUID();
// NOLINTNEXTLINE
namespace root {
void cacheSudo();
void dropSudo();
//
[[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool createDirectory(const std::string& path, const std::string& mode);
[[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool removeRecursive(const std::string& path);
[[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool install(const std::string& what, const std::string& where, const std::string& mode);
// Do not use this unless absolutely necessary!
std::string runAsSuperuserUnsafe(const std::string& cmd);
};
};

View File

@@ -2,34 +2,36 @@
#include "helpers/StringUtils.hpp" #include "helpers/StringUtils.hpp"
#include "core/PluginManager.hpp" #include "core/PluginManager.hpp"
#include "core/DataState.hpp" #include "core/DataState.hpp"
#include "helpers/Sys.hpp"
#include <cstdio>
#include <vector> #include <vector>
#include <string> #include <string>
#include <print> #include <print>
#include <chrono>
#include <thread> #include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::Utils;
constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
add [url] [git rev] Install a new plugin repository from git. Git revision add [url] [git rev] Install a new plugin repository from git. Git revision.
is optional, when set, commit locks are ignored. is optional, when set, commit locks are ignored.
remove [url/name] Remove an installed plugin repository remove [url/name] Remove an installed plugin repository.
enable [name] Enable a plugin enable [name] Enable a plugin.
disable [name] Disable a plugin disable [name] Disable a plugin.
update Check and update all plugins if needed update Check and update all plugins if needed.
reload Reload hyprpm state. Ensure all enabled plugins are loaded. reload Reload hyprpm state. Ensure all enabled plugins are loaded.
list List all installed plugins list List all installed plugins.
purge-cache Remove the entire hyprpm cache, built plugins, hyprpm settings and headers.
Flags: Flags:
--notify | -n Send a hyprland notification for important events (including both successes and fail events) --notify | -n Send a hyprland notification for important events (including both successes and fail events).
--notify-fail | -nn Send a hyprland notification for fail events only --notify-fail | -nn Send a hyprland notification for fail events only.
--help | -h Show this menu --help | -h Show this menu.
--verbose | -v Enable too much logging --verbose | -v Enable too much logging.
--force | -f Force an operation ignoring checks (e.g. update -f) --force | -f Force an operation ignoring checks (e.g. update -f).
--no-shallow | -s Disable shallow cloning of Hyprland sources --no-shallow | -s Disable shallow cloning of Hyprland sources.
--hl-url | Pass a custom hyprland source url --hl-url | Pass a custom hyprland source url.
)#"; )#";
@@ -96,9 +98,11 @@ int main(int argc, char** argv, char** envp) {
} }
std::string rev = ""; std::string rev = "";
if (command.size() >= 3) { if (command.size() >= 3)
rev = command[2]; rev = command[2];
}
NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1; return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
} else if (command[0] == "remove") { } else if (command[0] == "remove") {
@@ -107,10 +111,17 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} }
NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1; return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
} else if (command[0] == "update") { } else if (command[0] == "update") {
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK; NSys::root::cacheSudo();
bool headers = g_pPluginManager->updateHeaders(force); CScopeGuard x([] { NSys::root::dropSudo(); });
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
bool headers = g_pPluginManager->updateHeaders(force);
if (headers) { if (headers) {
const auto HLVER = g_pPluginManager->getHyprlandVersion(false); const auto HLVER = g_pPluginManager->getHyprlandVersion(false);
auto GLOBALSTATE = DataState::getGlobalState(); auto GLOBALSTATE = DataState::getGlobalState();
@@ -141,7 +152,10 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} }
auto ret = g_pPluginManager->ensurePluginsLoadState(); NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret == LOADSTATE_HYPRLAND_UPDATED) if (ret == LOADSTATE_HYPRLAND_UPDATED)
g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland."); g_pPluginManager->notify(ICON_INFO, 0, 10000, "[hyprpm] Enabled plugin, but Hyprland was updated. Please restart Hyprland.");
@@ -159,25 +173,36 @@ int main(int argc, char** argv, char** envp) {
return 1; return 1;
} }
auto ret = g_pPluginManager->ensurePluginsLoadState(); NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
auto ret = g_pPluginManager->ensurePluginsLoadState();
if (ret != LOADSTATE_OK) if (ret != LOADSTATE_OK)
return 1; return 1;
} else if (command[0] == "reload") { } else if (command[0] == "reload") {
auto ret = g_pPluginManager->ensurePluginsLoadState(force); auto ret = g_pPluginManager->ensurePluginsLoadState(force);
if (ret != LOADSTATE_OK && notify) { if (ret != LOADSTATE_OK) {
switch (ret) { if (notify) {
case LOADSTATE_FAIL: switch (ret) {
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break; case LOADSTATE_FAIL:
case LOADSTATE_HEADERS_OUTDATED: case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually."); case LOADSTATE_HEADERS_OUTDATED:
break; g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins: Outdated headers. Please run hyprpm update manually.");
default: break; break;
default: break;
}
} }
return 1; return 1;
} else if (notify && !notifyFail) { } else if (notify && !notifyFail) {
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins"); g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
} }
} else if (command[0] == "purge-cache") {
NSys::root::cacheSudo();
CScopeGuard x([] { NSys::root::dropSudo(); });
DataState::purgeAllCache();
} else if (command[0] == "list") { } else if (command[0] == "list") {
g_pPluginManager->listAllPlugins(); g_pPluginManager->listAllPlugins();
} else { } else {

View File

@@ -1,82 +1,78 @@
#include "CProgressBar.hpp" #include "CProgressBar.hpp"
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <algorithm> #include <unistd.h>
#include <cmath> #include <cmath>
#include <format> #include <format>
#include <print> #include <print>
#include <stdio.h> #include <cstdio>
#include <unistd.h>
#include <algorithm>
#include <sstream>
#include "../helpers/Colors.hpp" #include "../helpers/Colors.hpp"
void CProgressBar::printMessageAbove(const std::string& msg) { static winsize getTerminalSize() {
struct winsize w; winsize w{};
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
return w;
}
std::string spaces; static void clearCurrentLine() {
spaces.reserve(w.ws_col); std::print("\r\33[2K"); // ansi escape sequence to clear entire line
for (size_t i = 0; i < w.ws_col; ++i) { }
spaces += ' ';
}
std::println("\r{}\r{}", spaces, msg); void CProgressBar::printMessageAbove(const std::string& msg) {
print(); clearCurrentLine();
std::print("\r{}\n", msg);
print(); // reprint bar underneath
} }
void CProgressBar::print() { void CProgressBar::print() {
struct winsize w; const auto w = getTerminalSize();
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (m_bFirstPrint) if (m_bFirstPrint) {
std::print("\n"); std::print("\n");
m_bFirstPrint = false; m_bFirstPrint = false;
std::string spaces;
spaces.reserve(w.ws_col);
for (size_t i = 0; i < w.ws_col; ++i) {
spaces += ' ';
} }
std::print("\r{}\r", spaces); clearCurrentLine();
std::string message = ""; float percentDone = 0.0f;
if (m_fPercentage >= 0.0f)
float percentDone = 0;
if (m_fPercentage >= 0)
percentDone = m_fPercentage; percentDone = m_fPercentage;
else else {
percentDone = (float)m_iSteps / (float)m_iMaxSteps; // check for divide-by-zero
percentDone = m_iMaxSteps > 0 ? static_cast<float>(m_iSteps) / m_iMaxSteps : 0.0f;
const auto BARWIDTH = std::clamp(w.ws_col - static_cast<unsigned long>(m_szCurrentMessage.length()) - 2, 0UL, 50UL);
// draw bar
message += std::string{" "} + Colors::GREEN;
size_t i = 0;
for (; i < std::floor(percentDone * BARWIDTH); ++i) {
message += "";
} }
// clamp to ensure no overflows (sanity check)
percentDone = std::clamp(percentDone, 0.0f, 1.0f);
const size_t BARWIDTH = std::clamp<size_t>(w.ws_col - m_szCurrentMessage.length() - 2, 0, 50);
std::ostringstream oss;
oss << ' ' << Colors::GREEN;
size_t filled = static_cast<size_t>(std::floor(percentDone * BARWIDTH));
size_t i = 0;
for (; i < filled; ++i)
oss << "";
if (i < BARWIDTH) { if (i < BARWIDTH) {
i++; oss << "" << Colors::RESET;
++i;
message += std::string{""} + Colors::RESET; for (; i < BARWIDTH; ++i)
oss << "";
for (; i < BARWIDTH; ++i) {
message += "";
}
} else } else
message += Colors::RESET; oss << Colors::RESET;
// draw progress if (m_fPercentage >= 0.0f)
if (m_fPercentage >= 0) oss << " " << std::format("{}%", static_cast<int>(percentDone * 100.0)) << ' ';
message += " " + std::format("{}%", static_cast<int>(percentDone * 100.0)) + " ";
else else
message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " "; oss << " " << std::format("{} / {}", m_iSteps, m_iMaxSteps) << ' ';
// draw message
std::print("{} {}", message, m_szCurrentMessage);
std::print("{} {}", oss.str(), m_szCurrentMessage);
std::fflush(stdout); std::fflush(stdout);
} }

View File

@@ -31,11 +31,11 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif endif
aquamarine = dependency('aquamarine', version: '>=0.4.5') aquamarine = dependency('aquamarine', version: '>=0.8.0')
hyprcursor = dependency('hyprcursor', version: '>=0.1.7') hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1') hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
hyprlang = dependency('hyprlang', version: '>= 0.3.2') hyprlang = dependency('hyprlang', version: '>= 0.3.2')
hyprutils = dependency('hyprutils', version: '>= 0.2.3') hyprutils = dependency('hyprutils', version: '>= 0.7.0')
aquamarine_version_list = aquamarine.version().split('.') aquamarine_version_list = aquamarine.version().split('.')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
add_project_arguments(['-DAQUAMARINE_VERSION_MAJOR=@0@'.format(aquamarine_version_list.get(0))], language: 'cpp') add_project_arguments(['-DAQUAMARINE_VERSION_MAJOR=@0@'.format(aquamarine_version_list.get(0))], language: 'cpp')
@@ -87,9 +87,11 @@ endif
# Generate hyprland version and populate version.h # Generate hyprland version and populate version.h
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
# Make shader files includable
run_command('sh', '-c', 'scripts/generateShaderIncludes.sh', check: true)
# Install headers # Install headers
globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.frag', check: true) globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.inc', check: true)
headers = globber.stdout().strip().split('\n') headers = globber.stdout().strip().split('\n')
foreach file : headers foreach file : headers
install_headers(file, subdir: 'hyprland', preserve_path: true) install_headers(file, subdir: 'hyprland', preserve_path: true)

View File

@@ -11,6 +11,7 @@
aquamarine, aquamarine,
binutils, binutils,
cairo, cairo,
epoll-shim,
git, git,
glaze, glaze,
hyprcursor, hyprcursor,
@@ -141,6 +142,7 @@ in
wayland-scanner wayland-scanner
xorg.libXcursor xorg.libXcursor
] ]
(optionals customStdenv.hostPlatform.isBSD [ epoll-shim ])
(optionals customStdenv.hostPlatform.isMusl [libexecinfo]) (optionals customStdenv.hostPlatform.isMusl [libexecinfo])
(optionals enableXWayland [ (optionals enableXWayland [
xorg.libxcb xorg.libxcb
@@ -153,6 +155,8 @@ in
(optional withSystemd systemd) (optional withSystemd systemd)
]; ];
strictDeps = true;
mesonBuildType = mesonBuildType =
if debug if debug
then "debug" then "debug"
@@ -162,6 +166,7 @@ in
(mapAttrsToList mesonEnable { (mapAttrsToList mesonEnable {
"xwayland" = enableXWayland; "xwayland" = enableXWayland;
"legacy_renderer" = legacyRenderer; "legacy_renderer" = legacyRenderer;
"systemd" = withSystemd;
"uwsm" = false; "uwsm" = false;
"hyprpm" = false; "hyprpm" = false;
}) })

View File

@@ -126,13 +126,14 @@ in {
bottomCommandsPrefixes = cfg.bottomPrefixes; bottomCommandsPrefixes = cfg.bottomPrefixes;
} }
{ {
plugin = let "exec-once" = let
mkEntry = entry: mkEntry = entry:
if lib.types.package.check entry if lib.types.package.check entry
then "${entry}/lib/lib${entry.pname}.so" then "${entry}/lib/lib${entry.pname}.so"
else entry; else entry;
hyprctl = lib.getExe' config.programs.hyprland.package "hyprctl";
in in
map mkEntry cfg.plugins; map (p: "${hyprctl} plugin load ${mkEntry p}") cfg.plugins;
}; };
in in
lib.mkIf shouldGenerate { lib.mkIf shouldGenerate {

View File

@@ -29,6 +29,7 @@ in {
inputs.hyprutils.overlays.default inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default inputs.hyprwayland-scanner.overlays.default
self.overlays.udis86 self.overlays.udis86
self.overlays.wayland-protocols
# Hyprland packages themselves # Hyprland packages themselves
(final: _prev: let (final: _prev: let
@@ -89,4 +90,16 @@ in {
patches = []; patches = [];
}); });
}; };
# TODO: remove when https://github.com/NixOS/nixpkgs/pull/397497 lands in master
wayland-protocols = final: prev: {
wayland-protocols = prev.wayland-protocols.overrideAttrs (self: super: {
version = "1.43";
src = final.fetchurl {
url = "https://gitlab.freedesktop.org/wayland/${self.pname}/-/releases/${self.version}/downloads/${self.pname}-${self.version}.tar.xz";
hash = "sha256-ujw0Jd0nxXtSkek9upe+EkeWAeALyrJNJkcZSMtkNlM=";
};
});
};
} }

View File

@@ -1,13 +1,13 @@
wayland_protos = dependency( wayland_protos = dependency(
'wayland-protocols', 'wayland-protocols',
version: '>=1.41', version: '>=1.43',
fallback: 'wayland-protocols', fallback: 'wayland-protocols',
default_options: ['tests=false'], default_options: ['tests=false'],
) )
hyprland_protos = dependency( hyprland_protos = dependency(
'hyprland-protocols', 'hyprland-protocols',
version: '>=0.6.2', version: '>=0.6.4',
fallback: 'hyprland-protocols', fallback: 'hyprland-protocols',
) )
@@ -37,6 +37,7 @@ protocols = [
'frog-color-management-v1.xml', 'frog-color-management-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-mapping-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-surface-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-surface-v1.xml',
@@ -72,6 +73,8 @@ protocols = [
wayland_protocol_dir / 'staging/security-context/security-context-v1.xml', wayland_protocol_dir / 'staging/security-context/security-context-v1.xml',
wayland_protocol_dir / 'staging/content-type/content-type-v1.xml', wayland_protocol_dir / 'staging/content-type/content-type-v1.xml',
wayland_protocol_dir / 'staging/color-management/color-management-v1.xml', wayland_protocol_dir / 'staging/color-management/color-management-v1.xml',
wayland_protocol_dir / 'staging/xdg-toplevel-tag/xdg-toplevel-tag-v1.xml',
wayland_protocol_dir / 'staging/xdg-system-bell/xdg-system-bell-v1.xml',
] ]
wl_protocols = [] wl_protocols = []
@@ -87,7 +90,7 @@ foreach protocol : protocols
endforeach endforeach
# wayland.xml generation # wayland.xml generation
wayland_scanner = dependency('wayland-scanner') wayland_scanner = dependency('wayland-scanner', native: true)
wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir') wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir')
wayland_xml = wayland_scanner_datadir / 'wayland.xml' wayland_xml = wayland_scanner_datadir / 'wayland.xml'

View File

@@ -0,0 +1,24 @@
#!/bin/sh
SHADERS_SRC="./src/render/shaders/glsl"
echo "-- Generating shader includes"
if [ ! -d ./src/render/shaders ]; then
mkdir ./src/render/shaders
fi
echo '#pragma once' > ./src/render/shaders/Shaders.hpp
echo '#include <map>' >> ./src/render/shaders/Shaders.hpp
echo 'static const std::map<std::string, std::string> SHADERS = {' >> ./src/render/shaders/Shaders.hpp
for filename in `ls ${SHADERS_SRC}`; do
echo "-- ${filename}"
{ echo 'R"#('; cat ${SHADERS_SRC}/${filename}; echo ')#"'; } > ./src/render/shaders/${filename}.inc
echo "{\"${filename}\"," >> ./src/render/shaders/Shaders.hpp
echo "#include \"./${filename}.inc\"" >> ./src/render/shaders/Shaders.hpp
echo "}," >> ./src/render/shaders/Shaders.hpp
done
echo '};' >> ./src/render/shaders/Shaders.hpp

File diff suppressed because it is too large Load Diff

View File

@@ -25,53 +25,53 @@ class CCompositor {
CCompositor(bool onlyConfig = false); CCompositor(bool onlyConfig = false);
~CCompositor(); ~CCompositor();
wl_display* m_sWLDisplay = nullptr; wl_display* m_wlDisplay = nullptr;
wl_event_loop* m_sWLEventLoop = nullptr; wl_event_loop* m_wlEventLoop = nullptr;
int m_iDRMFD = -1; int m_drmFD = -1;
bool m_bInitialized = false; bool m_initialized = false;
SP<Aquamarine::CBackend> m_pAqBackend; SP<Aquamarine::CBackend> m_aqBackend;
std::string m_szHyprTempDataRoot = ""; std::string m_hyprTempDataRoot = "";
std::string m_szWLDisplaySocket = ""; std::string m_wlDisplaySocket = "";
std::string m_szInstanceSignature = ""; std::string m_instanceSignature = "";
std::string m_szInstancePath = ""; std::string m_instancePath = "";
std::string m_szCurrentSplash = "error"; std::string m_currentSplash = "error";
std::vector<PHLMONITOR> m_vMonitors; std::vector<PHLMONITOR> m_monitors;
std::vector<PHLMONITOR> m_vRealMonitors; // for all monitors, even those turned off std::vector<PHLMONITOR> m_realMonitors; // for all monitors, even those turned off
std::vector<PHLWINDOW> m_vWindows; std::vector<PHLWINDOW> m_windows;
std::vector<PHLLS> m_vLayers; std::vector<PHLLS> m_layers;
std::vector<PHLWORKSPACE> m_vWorkspaces; std::vector<PHLWORKSPACE> m_workspaces;
std::vector<PHLWINDOWREF> m_vWindowsFadingOut; std::vector<PHLWINDOWREF> m_windowsFadingOut;
std::vector<PHLLSREF> m_vSurfacesFadingOut; std::vector<PHLLSREF> m_surfacesFadingOut;
std::unordered_map<std::string, MONITORID> m_mMonitorIDMap; std::unordered_map<std::string, MONITORID> m_monitorIDMap;
std::unordered_map<std::string, WORKSPACEID> m_seenMonitorWorkspaceMap; // map of seen monitor names to workspace IDs
void initServer(std::string socketName, int socketFd); void initServer(std::string socketName, int socketFd);
void startCompositor(); void startCompositor();
void stopCompositor(); void stopCompositor();
void cleanup(); void cleanup();
void bumpNofile(); void bumpNofile();
void restoreNofile(); void restoreNofile();
WP<CWLSurfaceResource> m_pLastFocus; WP<CWLSurfaceResource> m_lastFocus;
PHLWINDOWREF m_pLastWindow; PHLWINDOWREF m_lastWindow;
PHLMONITORREF m_pLastMonitor; PHLMONITORREF m_lastMonitor;
std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused. std::vector<PHLWINDOWREF> m_windowFocusHistory; // first element is the most recently focused
bool m_bReadyToProcess = false; bool m_readyToProcess = false;
bool m_bSessionActive = true; bool m_sessionActive = true;
bool m_bDPMSStateON = true; bool m_dpmsStateOn = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_unsafeState = false; // unsafe state is when there is no monitors
bool m_bNextIsUnsafe = false; PHLMONITORREF m_unsafeOutput; // fallback output for the unsafe state
PHLMONITORREF m_pUnsafeOutput; // fallback output for the unsafe state bool m_isShuttingDown = false;
bool m_bIsShuttingDown = false; bool m_finalRequests = false;
bool m_bFinalRequests = false; bool m_desktopEnvSet = false;
bool m_bDesktopEnvSet = false; bool m_wantsXwayland = true;
bool m_bWantsXwayland = true; bool m_onlyConfigVerification = false;
bool m_bOnlyConfigVerification = false;
// ------------------------------------------------- // // ------------------------------------------------- //
@@ -85,7 +85,7 @@ class CCompositor {
void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr); void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr);
bool monitorExists(PHLMONITOR); bool monitorExists(PHLMONITOR);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerSurface(const Vector2D&, std::vector<PHLLSREF>*, Vector2D*, PHLLS*, bool aboveLockscreen = false);
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, PHLMONITOR monitor, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, PHLMONITOR monitor, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
@@ -152,7 +152,7 @@ class CCompositor {
NColorManagement::SImageDescription getPreferredImageDescription(); NColorManagement::SImageDescription getPreferredImageDescription();
bool shouldChangePreferredImageDescription(); bool shouldChangePreferredImageDescription();
std::string explicitConfigPath; std::string m_explicitConfigPath;
private: private:
void initAllSignals(); void initAllSignals();
@@ -165,9 +165,9 @@ class CCompositor {
void removeLockFile(); void removeLockFile();
void setMallocThreshold(); void setMallocThreshold();
uint64_t m_iHyprlandPID = 0; uint64_t m_hyprlandPID = 0;
wl_event_source* m_critSigSource = nullptr; wl_event_source* m_critSigSource = nullptr;
rlimit m_sOriginalNofile = {}; rlimit m_originalNofile = {};
}; };
inline UP<CCompositor> g_pCompositor; inline UP<CCompositor> g_pCompositor;

View File

@@ -2,11 +2,13 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/varlist/VarList.hpp" #include "../helpers/varlist/VarList.hpp"
#include <vector> #include <vector>
#include <map>
enum eConfigValueDataTypes : int8_t { enum eConfigValueDataTypes : int8_t {
CVD_TYPE_INVALID = -1, CVD_TYPE_INVALID = -1,
CVD_TYPE_GRADIENT = 0, CVD_TYPE_GRADIENT = 0,
CVD_TYPE_CSS_VALUE = 1 CVD_TYPE_CSS_VALUE = 1,
CVD_TYPE_FONT_WEIGHT = 2,
}; };
class ICustomConfigValueData { class ICustomConfigValueData {
@@ -22,7 +24,7 @@ class CGradientValueData : public ICustomConfigValueData {
public: public:
CGradientValueData() = default; CGradientValueData() = default;
CGradientValueData(CHyprColor col) { CGradientValueData(CHyprColor col) {
m_vColors.push_back(col); m_colors.push_back(col);
updateColorsOk(); updateColorsOk();
}; };
virtual ~CGradientValueData() = default; virtual ~CGradientValueData() = default;
@@ -32,39 +34,39 @@ class CGradientValueData : public ICustomConfigValueData {
} }
void reset(CHyprColor col) { void reset(CHyprColor col) {
m_vColors.clear(); m_colors.clear();
m_vColors.emplace_back(col); m_colors.emplace_back(col);
m_fAngle = 0; m_angle = 0;
updateColorsOk(); updateColorsOk();
} }
void updateColorsOk() { void updateColorsOk() {
m_vColorsOkLabA.clear(); m_colorsOkLabA.clear();
for (auto& c : m_vColors) { for (auto& c : m_colors) {
const auto OKLAB = c.asOkLab(); const auto OKLAB = c.asOkLab();
m_vColorsOkLabA.emplace_back(OKLAB.l); m_colorsOkLabA.emplace_back(OKLAB.l);
m_vColorsOkLabA.emplace_back(OKLAB.a); m_colorsOkLabA.emplace_back(OKLAB.a);
m_vColorsOkLabA.emplace_back(OKLAB.b); m_colorsOkLabA.emplace_back(OKLAB.b);
m_vColorsOkLabA.emplace_back(c.a); m_colorsOkLabA.emplace_back(c.a);
} }
} }
/* Vector containing the colors */ /* Vector containing the colors */
std::vector<CHyprColor> m_vColors; std::vector<CHyprColor> m_colors;
/* Vector containing pure colors for shoving into opengl */ /* Vector containing pure colors for shoving into opengl */
std::vector<float> m_vColorsOkLabA; std::vector<float> m_colorsOkLabA;
/* Float corresponding to the angle (rad) */ /* Float corresponding to the angle (rad) */
float m_fAngle = 0; float m_angle = 0;
// //
bool operator==(const CGradientValueData& other) const { bool operator==(const CGradientValueData& other) const {
if (other.m_vColors.size() != m_vColors.size() || m_fAngle != other.m_fAngle) if (other.m_colors.size() != m_colors.size() || m_angle != other.m_angle)
return false; return false;
for (size_t i = 0; i < m_vColors.size(); ++i) for (size_t i = 0; i < m_colors.size(); ++i)
if (m_vColors[i] != other.m_vColors[i]) if (m_colors[i] != other.m_colors[i])
return false; return false;
return true; return true;
@@ -72,28 +74,28 @@ class CGradientValueData : public ICustomConfigValueData {
virtual std::string toString() { virtual std::string toString() {
std::string result; std::string result;
for (auto& c : m_vColors) { for (auto& c : m_colors) {
result += std::format("{:x} ", c.getAsHex()); result += std::format("{:x} ", c.getAsHex());
} }
result += std::format("{}deg", (int)(m_fAngle * 180.0 / M_PI)); result += std::format("{}deg", (int)(m_angle * 180.0 / M_PI));
return result; return result;
} }
}; };
class CCssGapData : public ICustomConfigValueData { class CCssGapData : public ICustomConfigValueData {
public: public:
CCssGapData() : top(0), right(0), bottom(0), left(0) {}; CCssGapData() : m_top(0), m_right(0), m_bottom(0), m_left(0) {};
CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global) {}; CCssGapData(int64_t global) : m_top(global), m_right(global), m_bottom(global), m_left(global) {};
CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal) {}; CCssGapData(int64_t vertical, int64_t horizontal) : m_top(vertical), m_right(horizontal), m_bottom(vertical), m_left(horizontal) {};
CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : top(top), right(horizontal), bottom(bottom), left(horizontal) {}; CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : m_top(top), m_right(horizontal), m_bottom(bottom), m_left(horizontal) {};
CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : top(top), right(right), bottom(bottom), left(left) {}; CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : m_top(top), m_right(right), m_bottom(bottom), m_left(left) {};
/* Css like directions */ /* Css like directions */
int64_t top; int64_t m_top;
int64_t right; int64_t m_right;
int64_t bottom; int64_t m_bottom;
int64_t left; int64_t m_left;
void parseGapData(CVarList varlist) { void parseGapData(CVarList varlist) {
switch (varlist.size()) { switch (varlist.size()) {
@@ -122,10 +124,10 @@ class CCssGapData : public ICustomConfigValueData {
} }
void reset(int64_t global) { void reset(int64_t global) {
top = global; m_top = global;
right = global; m_right = global;
bottom = global; m_bottom = global;
left = global; m_left = global;
} }
virtual eConfigValueDataTypes getDataType() { virtual eConfigValueDataTypes getDataType() {
@@ -133,6 +135,44 @@ class CCssGapData : public ICustomConfigValueData {
} }
virtual std::string toString() { virtual std::string toString() {
return std::format("{} {} {} {}", top, right, bottom, left); return std::format("{} {} {} {}", m_top, m_right, m_bottom, m_left);
}
};
class CFontWeightConfigValueData : public ICustomConfigValueData {
public:
CFontWeightConfigValueData() = default;
CFontWeightConfigValueData(const char* weight) {
parseWeight(weight);
}
int64_t m_value = 400; // default to normal weight
virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_FONT_WEIGHT;
}
virtual std::string toString() {
return std::format("{}", m_value);
}
void parseWeight(const std::string& strWeight) {
auto lcWeight{strWeight};
transform(strWeight.begin(), strWeight.end(), lcWeight.begin(), ::tolower);
// values taken from Pango weight enums
const auto WEIGHTS = std::map<std::string, int>{
{"thin", 100}, {"ultralight", 200}, {"light", 300}, {"semilight", 350}, {"book", 380}, {"normal", 400},
{"medium", 500}, {"semibold", 600}, {"bold", 700}, {"ultrabold", 800}, {"heavy", 900}, {"ultraheavy", 1000},
};
auto weight = WEIGHTS.find(lcWeight);
if (weight != WEIGHTS.end())
m_value = weight->second;
else {
int w_i = std::stoi(strWeight);
if (w_i < 100 || w_i > 1000)
m_value = 400;
}
} }
}; };

View File

@@ -247,6 +247,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_STRING_LONG, .type = CONFIG_OPTION_STRING_LONG,
.data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET?
}, },
SConfigOptionDescription{
.value = "decoration:border_part_of_window",
.description = "whether the border should be treated as a part of the window.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
/* /*
* blur: * blur:
@@ -366,6 +372,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "animations:workspace_wraparound",
.description = "changes the direction of slide animations between the first and last workspaces",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
/* /*
* input: * input:
@@ -891,6 +903,18 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_STRING_SHORT, .type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET? .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET?
}, },
SConfigOptionDescription{
.value = "group:groupbar:font_weight_active",
.description = "weight of the font used to display active groupbar titles",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"normal"},
},
SConfigOptionDescription{
.value = "group:groupbar:font_weight_inactive",
.description = "weight of the font used to display inactive groupbar titles",
.type = CONFIG_OPTION_STRING_SHORT,
.data = SConfigOptionDescription::SStringData{"normal"},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:font_size", .value = "group:groupbar:font_size",
.description = "font size of groupbar title", .description = "font size of groupbar title",
@@ -909,6 +933,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{14, 1, 64}, .data = SConfigOptionDescription::SRangeData{14, 1, 64},
}, },
SConfigOptionDescription{
.value = "group:groupbar:indicator_gap",
.description = "height of the gap between the groupbar indicator and title",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{0, 0, 64},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "group:groupbar:indicator_height", .value = "group:groupbar:indicator_height",
.description = "height of the groupbar indicator", .description = "height of the groupbar indicator",
@@ -1005,6 +1035,18 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 20}, .data = SConfigOptionDescription::SRangeData{2, 0, 20},
}, },
SConfigOptionDescription{
.value = "group:groupbar:keep_upper_gap",
.description = "keep an upper gap above gradient",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "group:groupbar:text_offset",
.description = "set an offset for a text",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SRangeData{0, -20, 20},
},
/* /*
* misc: * misc:
@@ -1054,9 +1096,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "misc:vrr", .value = "misc:vrr",
.description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only [0/1/2]", .description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only, 3 - fullscreen with game or video content type [0/1/2/3]",
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{0, 0, 2}, .data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 3},
}, },
SConfigOptionDescription{ SConfigOptionDescription{
.value = "misc:mouse_move_enables_dpms", .value = "misc:mouse_move_enables_dpms",
@@ -1217,6 +1259,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
SConfigOptionDescription{
.value = "misc:anr_missed_pings",
.description = "number of missed pings before showing the ANR dialog",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{1, 1, 10},
},
/* /*
* binds: * binds:
@@ -1240,6 +1288,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "binds:hide_special_on_workspace_change",
.description = "If enabled, changing the active workspace (including to itself) will hide the special workspace on the monitor where the newly active workspace resides.",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "binds:allow_workspace_cycles", .value = "binds:allow_workspace_cycles",
.description = "If enabled, workspaces dont forget their previous workspace, so cycles can be created by switching to the first workspace in a sequence, then endlessly " .description = "If enabled, workspaces dont forget their previous workspace, so cycles can be created by switching to the first workspace in a sequence, then endlessly "
@@ -1296,6 +1350,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "binds:drag_threshold",
.description = "Movement threshold in pixels for window dragging and c/g bind flags. 0 to disable and grab on mousedown.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{0, 0, INT_MAX},
},
/* /*
* xwayland: * xwayland:
@@ -1319,6 +1379,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "xwayland:create_abstract_socket",
.description = "Create the abstract Unix domain socket for XWayland",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false},
},
/* /*
* opengl: * opengl:
@@ -1375,6 +1441,18 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
SConfigOptionDescription{ SConfigOptionDescription{
.value = "render:cm_fs_passthrough", .value = "render:cm_fs_passthrough",
.description = "Passthrough color settings for fullscreen apps when possible", .description = "Passthrough color settings for fullscreen apps when possible",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2},
},
SConfigOptionDescription{
.value = "render:cm_enabled",
.description = "Enable Color Management pipelines (requires restart to fully take effect)",
.type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{
.value = "render:send_content_type",
.description = "Report content type to allow monitor profile autoswitch (may result in a black screen during the switch)",
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{true}, .data = SConfigOptionDescription::SBoolData{true},
}, },
@@ -1432,6 +1510,13 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_CHOICE, .type = CONFIG_OPTION_CHOICE,
.data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"}, .data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Force"},
}, },
SConfigOptionDescription{
.value = "cursor:warp_on_toggle_special",
.description = "Move the cursor to the last focused window when toggling a special 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{ SConfigOptionDescription{
.value = "cursor:default_monitor", .value = "cursor:default_monitor",
.description = "the name of a default monitor for the cursor to be set to on startup (see hyprctl monitors for names)", .description = "the name of a default monitor for the cursor to be set to on startup (see hyprctl monitors for names)",
@@ -1556,12 +1641,6 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_BOOL, .type = CONFIG_OPTION_BOOL,
.data = SConfigOptionDescription::SBoolData{false}, .data = SConfigOptionDescription::SBoolData{false},
}, },
SConfigOptionDescription{
.value = "debug:watchdog_timeout",
.description = "sets the timeout in seconds for watchdog to abort processing of a signal of the main thread. Set to 0 to disable.",
.type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{5, 0, 20},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "debug:disable_scale_checks", .value = "debug:disable_scale_checks",
.description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.", .description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.",
@@ -1738,12 +1817,10 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
.type = CONFIG_OPTION_INT, .type = CONFIG_OPTION_INT,
.data = SConfigOptionDescription::SRangeData{2, 0, 10}, //##TODO RANGE? .data = SConfigOptionDescription::SRangeData{2, 0, 10}, //##TODO RANGE?
}, },
SConfigOptionDescription{ SConfigOptionDescription{.value = "master:center_master_fallback",
.value = "master:center_master_slaves_on_right", .description = "Set fallback for center master when slaves are less than slave_count_for_center_master, can be left ,right ,top ,bottom",
.description = "set if the slaves should appear on right of master when slave_count_for_center_master > 2", .type = CONFIG_OPTION_STRING_SHORT,
.type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SStringData{"left"}},
.data = SConfigOptionDescription::SBoolData{true},
},
SConfigOptionDescription{ SConfigOptionDescription{
.value = "master:center_ignores_reserved", .value = "master:center_ignores_reserved",
.description = "centers the master window on monitor ignoring reserved areas", .description = "centers the master window on monitor ignoring reserved areas",

File diff suppressed because it is too large Load Diff

View File

@@ -141,8 +141,18 @@ struct SFirstExecRequest {
struct SFloatCache { struct SFloatCache {
size_t hash; size_t hash;
SFloatCache(PHLWINDOW window) { SFloatCache(PHLWINDOW window, bool initial) {
hash = std::hash<std::string>{}(window->m_szClass) ^ (std::hash<std::string>{}(window->m_szTitle) << 1); // Base hash from class/title
size_t baseHash = initial ? (std::hash<std::string>{}(window->m_initialClass) ^ (std::hash<std::string>{}(window->m_initialTitle) << 1)) :
(std::hash<std::string>{}(window->m_class) ^ (std::hash<std::string>{}(window->m_title) << 1));
// Use empty string as default tag value
std::string tagValue = "";
if (auto xdgTag = window->xdgTag())
tagValue = xdgTag.value();
// Combine hashes
hash = baseHash ^ (std::hash<std::string>{}(tagValue) << 2);
} }
bool operator==(const SFloatCache& other) const { bool operator==(const SFloatCache& other) const {
@@ -235,7 +245,6 @@ class CConfigManager {
std::optional<std::string> handleUnbind(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> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(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> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(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> handleAnimation(const std::string&, const std::string&);
@@ -245,48 +254,49 @@ class CConfigManager {
std::optional<std::string> handleBindWS(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> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&); std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::optional<std::string> handlePermission(const std::string&, const std::string&);
std::string configCurrentPath; std::string m_configCurrentPath;
bool m_bWantsMonitorReload = false; bool m_wantsMonitorReload = false;
bool m_bNoMonitorReload = false; bool m_noMonitorReload = false;
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking bool m_isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
bool m_bLastConfigVerificationWasSuccessful = true; bool m_lastConfigVerificationWasSuccessful = true;
void storeFloatingSize(PHLWINDOW window, const Vector2D& size); void storeFloatingSize(PHLWINDOW window, const Vector2D& size);
std::optional<Vector2D> getStoredFloatingSize(PHLWINDOW window); std::optional<Vector2D> getStoredFloatingSize(PHLWINDOW window);
private: private:
UP<Hyprlang::CConfig> m_pConfig; UP<Hyprlang::CConfig> m_config;
std::vector<std::string> m_configPaths; std::vector<std::string> m_configPaths;
Hyprutils::Animation::CAnimationConfigTree m_AnimationTree; Hyprutils::Animation::CAnimationConfigTree m_animationTree;
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap std::string m_currentSubmap = ""; // For storing the current keybind submap
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty std::vector<SExecRequestedRule> m_execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
std::vector<std::string> m_vDeclaredPlugins; std::vector<std::string> m_declaredPlugins;
std::vector<SPluginKeyword> pluginKeywords; std::vector<SPluginKeyword> m_pluginKeywords;
std::vector<SPluginVariable> pluginVariables; std::vector<SPluginVariable> m_pluginVariables;
bool isFirstLaunch = true; // For exec-once bool m_isFirstLaunch = true; // For exec-once
std::vector<SMonitorRule> m_vMonitorRules; std::vector<SMonitorRule> m_monitorRules;
std::vector<SWorkspaceRule> m_vWorkspaceRules; std::vector<SWorkspaceRule> m_workspaceRules;
std::vector<SP<CWindowRule>> m_vWindowRules; std::vector<SP<CWindowRule>> m_windowRules;
std::vector<SP<CLayerRule>> m_vLayerRules; std::vector<SP<CLayerRule>> m_layerRules;
std::vector<std::string> m_dBlurLSNamespaces; std::vector<std::string> m_blurLSNamespaces;
bool firstExecDispatched = false; bool m_firstExecDispatched = false;
bool m_bManualCrashInitiated = false; bool m_manualCrashInitiated = false;
std::vector<SFirstExecRequest> firstExecRequests; // bool is for if with rules std::vector<SFirstExecRequest> m_firstExecRequests; // bool is for if with rules
std::vector<std::string> finalExecRequests; std::vector<std::string> m_finalExecRequests;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins std::vector<std::pair<std::string, std::string>> m_failedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_szConfigErrors = ""; std::string m_configErrors = "";
uint32_t m_configValueNumber = 0; uint32_t m_configValueNumber = 0;

View File

@@ -0,0 +1,15 @@
#include "ConfigValue.hpp"
#include "ConfigManager.hpp"
#include "../macros.hpp"
void local__configValuePopulate(void* const** p, const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
*p = PVHYPRLANG->getDataStaticPtr();
}
std::type_index local__configValueTypeIdx(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
const auto ANY = PVHYPRLANG->getValue();
return std::type_index(ANY.type());
}

View File

@@ -4,21 +4,19 @@
#include <typeindex> #include <typeindex>
#include <hyprlang.hpp> #include <hyprlang.hpp>
#include "../macros.hpp" #include "../macros.hpp"
#include "ConfigManager.hpp"
// giga hack to avoid including configManager here
// NOLINTNEXTLINE
void local__configValuePopulate(void* const** p, const std::string& val);
std::type_index local__configValueTypeIdx(const std::string& val);
template <typename T> template <typename T>
class CConfigValue { class CConfigValue {
public: public:
CConfigValue(const std::string& val) { CConfigValue(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
// NOLINTNEXTLINE
p_ = PVHYPRLANG->getDataStaticPtr();
#ifdef HYPRLAND_DEBUG #ifdef HYPRLAND_DEBUG
// verify type // verify type
const auto ANY = PVHYPRLANG->getValue(); const auto TYPE = local__configValueTypeIdx(val);
const auto TYPE = std::type_index(ANY.type());
// exceptions // exceptions
const bool STRINGEX = (typeid(T) == typeid(std::string) && TYPE == typeid(Hyprlang::STRING)); const bool STRINGEX = (typeid(T) == typeid(std::string) && TYPE == typeid(Hyprlang::STRING));
@@ -26,6 +24,8 @@ class CConfigValue {
RASSERT(typeid(T) == TYPE || STRINGEX || CUSTOMEX, "Mismatched type in CConfigValue<T>, got {} but has {}", typeid(T).name(), TYPE.name()); RASSERT(typeid(T) == TYPE || STRINGEX || CUSTOMEX, "Mismatched type in CConfigValue<T>, got {} but has {}", typeid(T).name(), TYPE.name());
#endif #endif
local__configValuePopulate(&p_, val);
} }
T* ptr() const { T* ptr() const {

View File

@@ -65,6 +65,23 @@ env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24 env = HYPRCURSOR_SIZE,24
###################
### PERMISSIONS ###
###################
# See https://wiki.hyprland.org/Configuring/Permissions/
# Please note permission changes here require a Hyprland restart and are not applied on-the-fly
# for security reasons
# ecosystem {
# enforce_permissions = 1
# }
# permission = /usr/(bin|local/bin)/grim, screencopy, allow
# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow
##################### #####################
### LOOK AND FEEL ### ### LOOK AND FEEL ###
##################### #####################
@@ -152,10 +169,10 @@ animations {
# uncomment all if you wish to use that. # uncomment all if you wish to use that.
# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = w[tv1], gapsout:0, gapsin:0
# workspace = f[1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1] # windowrule = bordersize 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1] # windowrule = rounding 0, floating:0, onworkspace:w[tv1]
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1] # windowrule = bordersize 0, floating:0, onworkspace:f[1]
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1] # windowrule = rounding 0, floating:0, onworkspace:f[1]
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
dwindle { dwindle {
@@ -269,12 +286,12 @@ bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness # Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-
# Requires playerctl # Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next bindl = , XF86AudioNext, exec, playerctl next
@@ -289,15 +306,12 @@ bindl = , XF86AudioPrev, exec, playerctl previous
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more # See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules # See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
# Example windowrule v1 # Example windowrule
# windowrule = float, ^(kitty)$ # windowrule = float,class:^(kitty)$,title:^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# Ignore maximize requests from apps. You'll probably like this. # Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.* windowrule = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland # Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
)#"; )#";

View File

@@ -130,11 +130,11 @@ void NCrashReporter::createAndSaveCrash(int sig) {
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
auto p = plugins[i]; auto p = plugins[i];
finalCrashReport += '\t'; finalCrashReport += '\t';
finalCrashReport += p->name; finalCrashReport += p->m_name;
finalCrashReport += " ("; finalCrashReport += " (";
finalCrashReport += p->author; finalCrashReport += p->m_author;
finalCrashReport += ") "; finalCrashReport += ") ";
finalCrashReport += p->version; finalCrashReport += p->m_version;
finalCrashReport += '\n'; finalCrashReport += '\n';
} }
@@ -192,7 +192,7 @@ void NCrashReporter::createAndSaveCrash(int sig) {
#endif #endif
}; };
u_int miblen = sizeof(mib) / sizeof(mib[0]); u_int miblen = sizeof(mib) / sizeof(mib[0]);
char exe[PATH_MAX] = ""; char exe[PATH_MAX] = "/nonexistent";
size_t sz = sizeof(exe); size_t sz = sizeof(exe);
sysctl(mib, miblen, &exe, &sz, NULL, 0); sysctl(mib, miblen, &exe, &sz, NULL, 0);
const auto FPATH = std::filesystem::canonical(exe); const auto FPATH = std::filesystem::canonical(exe);
@@ -242,5 +242,5 @@ void NCrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += "\n\nLog tail:\n"; finalCrashReport += "\n\nLog tail:\n";
finalCrashReport += std::string_view(Debug::rollingLog).substr(Debug::rollingLog.find('\n') + 1); finalCrashReport += std::string_view(Debug::m_rollingLog).substr(Debug::m_rollingLog.find('\n') + 1);
} }

View File

@@ -17,6 +17,7 @@
#include <sys/poll.h> #include <sys/poll.h>
#include <filesystem> #include <filesystem>
#include <ranges> #include <ranges>
#include <sys/eventfd.h>
#include <sstream> #include <sstream>
#include <string> #include <string>
@@ -24,6 +25,7 @@
#include <numeric> #include <numeric>
#include <hyprutils/string/String.hpp> #include <hyprutils/string/String.hpp>
#include <hyprutils/os/FileDescriptor.hpp>
using namespace Hyprutils::String; using namespace Hyprutils::String;
using namespace Hyprutils::OS; using namespace Hyprutils::OS;
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>
@@ -51,6 +53,29 @@ using namespace Hyprutils::OS;
#include "../managers/AnimationManager.hpp" #include "../managers/AnimationManager.hpp"
#include "../debug/HyprNotificationOverlay.hpp" #include "../debug/HyprNotificationOverlay.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
#include "../render/OpenGL.hpp"
#if defined(__DragonFly__) || defined(__FreeBSD__)
#include <sys/ucred.h>
#define CRED_T xucred
#define CRED_LVL SOL_LOCAL
#define CRED_OPT LOCAL_PEERCRED
#define CRED_PID cr_pid
#elif defined(__NetBSD__)
#define CRED_T unpcbid
#define CRED_LVL SOL_LOCAL
#define CRED_OPT LOCAL_PEEREID
#define CRED_PID unp_pid
#else
#if defined(__OpenBSD__)
#define CRED_T sockpeercred
#else
#define CRED_T ucred
#endif
#define CRED_LVL SOL_SOCKET
#define CRED_OPT SO_PEERCRED
#define CRED_PID pid
#endif
static void trimTrailingComma(std::string& str) { static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',') if (!str.empty() && str.back() == ',')
@@ -72,7 +97,7 @@ static std::string formatToString(uint32_t drmFormat) {
static std::string availableModesForOutput(PHLMONITOR pMonitor, eHyprCtlOutputFormat format) { static std::string availableModesForOutput(PHLMONITOR pMonitor, eHyprCtlOutputFormat format) {
std::string result; std::string result;
for (auto const& m : pMonitor->output->modes) { for (auto const& m : pMonitor->m_output->modes) {
if (format == FORMAT_NORMAL) if (format == FORMAT_NORMAL)
result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0); result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0);
else else
@@ -86,7 +111,7 @@ static std::string availableModesForOutput(PHLMONITOR pMonitor, eHyprCtlOutputFo
std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) { std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) {
std::string result; std::string result;
if (!m->output || m->ID == -1) if (!m->m_output || m->m_id == -1)
return ""; return "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@@ -127,27 +152,28 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"availableModes": [{}] "availableModes": [{}]
}},)#", }},)#",
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make), escapeJSONStrings(m->output->model), m->m_id, escapeJSONStrings(m->m_name), escapeJSONStrings(m->m_shortDescription), escapeJSONStrings(m->m_output->make), escapeJSONStrings(m->m_output->model),
escapeJSONStrings(m->output->serial), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, escapeJSONStrings(m->m_output->serial), (int)m->m_pixelSize.x, (int)m->m_pixelSize.y, m->m_refreshRate, (int)m->m_position.x, (int)m->m_position.y,
m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), m->activeWorkspaceID(), (!m->m_activeWorkspace ? "" : escapeJSONStrings(m->m_activeWorkspace->m_name)), m->activeSpecialWorkspaceID(),
escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, escapeJSONStrings(m->m_activeSpecialWorkspace ? m->m_activeSpecialWorkspace->m_name : ""), (int)m->m_reservedTopLeft.x, (int)m->m_reservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (int)m->m_reservedBottomRight.x, (int)m->m_reservedBottomRight.y, m->m_scale, (int)m->m_transform, (m == g_pCompositor->m_lastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(), (m->m_dpmsStatus ? "true" : "false"), (m->m_output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->m_solitaryClient.get(),
(m->tearingState.activelyTearing ? "true" : "false"), (uint64_t)m->lastScanout.get(), (m->m_bEnabled ? "false" : "true"), (m->m_tearingState.activelyTearing ? "true" : "false"), (uint64_t)m->m_lastScanout.get(), (m->m_enabled ? "false" : "true"),
formatToString(m->output->state->state().drmFormat), m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format)); formatToString(m->m_output->state->state().drmFormat), m->m_mirrorOf ? std::format("{}", m->m_mirrorOf->m_id) : "none", availableModesForOutput(m, format));
} else { } 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" result +=
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdirectScanoutTo: {:x}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tmirrorOf: " "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"{}\n\tavailableModes: {}\n\n", "dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdirectScanoutTo: {:x}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tmirrorOf: "
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, "{}\n\tavailableModes: {}\n\n",
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->m_name, m->m_id, (int)m->m_pixelSize.x, (int)m->m_pixelSize.y, m->m_refreshRate, (int)m->m_position.x, (int)m->m_position.y, m->m_shortDescription,
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, m->m_output->make, m->m_output->model, m->m_output->serial, m->activeWorkspaceID(), (!m->m_activeWorkspace ? "" : m->m_activeWorkspace->m_name),
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, m->activeSpecialWorkspaceID(), (m->m_activeSpecialWorkspace ? m->m_activeSpecialWorkspace->m_name : ""), (int)m->m_reservedTopLeft.x,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(), (int)m->m_reservedTopLeft.y, (int)m->m_reservedBottomRight.x, (int)m->m_reservedBottomRight.y, m->m_scale, (int)m->m_transform,
m->tearingState.activelyTearing, (uint64_t)m->lastScanout.get(), !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), (m == g_pCompositor->m_lastMonitor ? "yes" : "no"), (int)m->m_dpmsStatus, m->m_output->state->state().adaptiveSync, (uint64_t)m->m_solitaryClient.get(),
m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format)); m->m_tearingState.activelyTearing, (uint64_t)m->m_lastScanout.get(), !m->m_enabled, formatToString(m->m_output->state->state().drmFormat),
m->m_mirrorOf ? std::format("{}", m->m_mirrorOf->m_id) : "none", availableModesForOutput(m, format));
} }
return result; return result;
@@ -167,7 +193,7 @@ static std::string monitorsRequest(eHyprCtlOutputFormat format, std::string requ
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto const& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { for (auto const& m : allMonitors ? g_pCompositor->m_realMonitors : g_pCompositor->m_monitors) {
result += CHyprCtl::getMonitorData(m, format); result += CHyprCtl::getMonitorData(m, format);
} }
@@ -175,8 +201,8 @@ static std::string monitorsRequest(eHyprCtlOutputFormat format, std::string requ
result += "]"; result += "]";
} else { } else {
for (auto const& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { for (auto const& m : allMonitors ? g_pCompositor->m_realMonitors : g_pCompositor->m_monitors) {
if (!m->output || m->ID == -1) if (!m->m_output || m->m_id == -1)
continue; continue;
result += CHyprCtl::getMonitorData(m, format); result += CHyprCtl::getMonitorData(m, format);
@@ -198,7 +224,7 @@ static std::string getTagsData(PHLWINDOW w, eHyprCtlOutputFormat format) {
static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) { static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) {
const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON; const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON;
if (w->m_sGroupData.pNextWindow.expired()) if (w->m_groupData.pNextWindow.expired())
return isJson ? "" : "0"; return isJson ? "" : "0";
std::ostringstream result; std::ostringstream result;
@@ -210,7 +236,7 @@ static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) {
result << std::format("\"0x{:x}\"", (uintptr_t)curr.get()); result << std::format("\"0x{:x}\"", (uintptr_t)curr.get());
else else
result << std::format("{:x}", (uintptr_t)curr.get()); result << std::format("{:x}", (uintptr_t)curr.get());
curr = curr->m_sGroupData.pNextWindow.lock(); curr = curr->m_groupData.pNextWindow.lock();
// We've wrapped around to the start, break out without trailing comma // We've wrapped around to the start, break out without trailing comma
if (curr == head) if (curr == head)
break; break;
@@ -222,8 +248,8 @@ static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) {
std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
auto getFocusHistoryID = [](PHLWINDOW wnd) -> int { auto getFocusHistoryID = [](PHLWINDOW wnd) -> int {
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) { for (size_t i = 0; i < g_pCompositor->m_windowFocusHistory.size(); ++i) {
if (g_pCompositor->m_vWindowFocusHistory[i].lock() == wnd) if (g_pCompositor->m_windowFocusHistory[i].lock() == wnd)
return i; return i;
} }
return -1; return -1;
@@ -257,27 +283,29 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"tags": [{}], "tags": [{}],
"swallowing": "0x{:x}", "swallowing": "0x{:x}",
"focusHistoryID": {}, "focusHistoryID": {},
"inhibitingIdle": {} "inhibitingIdle": {},
"xdgTag": "{}",
"xdgDescription": "{}"
}},)#", }},)#",
(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, (uintptr_t)w.get(), (w->m_isMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_realPosition->goal().x, (int)w->m_realPosition->goal().y,
(int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (int)w->m_realSize->goal().x, (int)w->m_realSize->goal().y, w->m_workspace ? w->workspaceID() : WORKSPACE_INVALID,
escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), escapeJSONStrings(!w->m_workspace ? "" : w->m_workspace->m_name), ((int)w->m_isFloating == 1 ? "true" : "false"), (w->m_isPseudotiled ? "true" : "false"),
(int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), (int64_t)w->monitorID(), escapeJSONStrings(w->m_class), escapeJSONStrings(w->m_title), escapeJSONStrings(w->m_initialClass), escapeJSONStrings(w->m_initialTitle),
escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), w->getPID(), ((int)w->m_isX11 == 1 ? "true" : "false"), (w->m_pinned ? "true" : "false"), (uint8_t)w->m_fullscreenState.internal, (uint8_t)w->m_fullscreenState.client,
(uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.get(), getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_swallowed.get(), getFocusHistoryID(w),
getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false")); (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false"), escapeJSONStrings(w->xdgTag().value_or("")), escapeJSONStrings(w->xdgDescription().value_or("")));
} else { } else {
return std::format( 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: " "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\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\txwayland: {}\n\tpinned: " "{}\n\txwayland: {}\n\tpinned: "
"{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\tinhibitingIdle: {}\n\n", "{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\tinhibitingIdle: {}\n\txdgTag: "
(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, "{}\n\txdgDescription: {}\n\n",
(int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (uintptr_t)w.get(), w->m_title, (int)w->m_isMapped, (int)w->isHidden(), (int)w->m_realPosition->goal().x, (int)w->m_realPosition->goal().y,
(!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, (int)w->m_realSize->goal().x, (int)w->m_realSize->goal().y, w->m_workspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_workspace ? "" : w->m_workspace->m_name),
w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (int)w->m_isFloating, (int)w->m_isPseudotiled, (int64_t)w->monitorID(), w->m_class, w->m_title, w->m_initialClass, w->m_initialTitle, w->getPID(), (int)w->m_isX11,
(uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.get(), getFocusHistoryID(w), (int)w->m_pinned, (uint8_t)w->m_fullscreenState.internal, (uint8_t)w->m_fullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
(int)g_pInputManager->isWindowInhibiting(w, false)); (uintptr_t)w->m_swallowed.get(), getFocusHistoryID(w), (int)g_pInputManager->isWindowInhibiting(w, false), w->xdgTag().value_or(""), w->xdgDescription().value_or(""));
} }
} }
@@ -286,8 +314,8 @@ static std::string clientsRequest(eHyprCtlOutputFormat format, std::string reque
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) if (!w->m_isMapped && !g_pHyprCtl->m_currentRequestParams.all)
continue; continue;
result += CHyprCtl::getWindowData(w, format); result += CHyprCtl::getWindowData(w, format);
@@ -297,8 +325,8 @@ static std::string clientsRequest(eHyprCtlOutputFormat format, std::string reque
result += "]"; result += "]";
} else { } else {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) if (!w->m_isMapped && !g_pHyprCtl->m_currentRequestParams.all)
continue; continue;
result += CHyprCtl::getWindowData(w, format); result += CHyprCtl::getWindowData(w, format);
@@ -309,7 +337,7 @@ static std::string clientsRequest(eHyprCtlOutputFormat format, std::string reque
std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) { std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) {
const auto PLASTW = w->getLastFocusedWindow(); const auto PLASTW = w->getLastFocusedWindow();
const auto PMONITOR = w->m_pMonitor.lock(); const auto PMONITOR = w->m_monitor.lock();
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
return std::format(R"#({{ return std::format(R"#({{
"id": {}, "id": {},
@@ -322,14 +350,14 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form
"lastwindowtitle": "{}", "lastwindowtitle": "{}",
"ispersistent": {} "ispersistent": {}
}})#", }})#",
w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"), w->m_id, escapeJSONStrings(w->m_name), escapeJSONStrings(PMONITOR ? PMONITOR->m_name : "?"),
escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), w->m_bHasFullscreenWindow ? "true" : "false", escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->m_id) : "null"), w->getWindows(), w->m_hasFullscreenWindow ? "true" : "false",
(uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "", w->m_bPersistent ? "true" : "false"); (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_title) : "", w->m_persistent ? "true" : "false");
} else { } else {
return std::format( return std::format(
"workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\tispersistent: {}\n\n", "workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\tispersistent: {}\n\n",
w->m_iID, w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow, w->m_id, w->m_name, PMONITOR ? PMONITOR->m_name : "?", PMONITOR ? std::to_string(PMONITOR->m_id) : "null", w->getWindows(), (int)w->m_hasFullscreenWindow,
(uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "", (int)w->m_bPersistent); (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_title : "", (int)w->m_persistent);
} }
} }
@@ -340,10 +368,10 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : ""; const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : "";
const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : ""; const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : "";
const std::string gapsIn = (bool)(r.gapsIn) ? const std::string gapsIn = (bool)(r.gapsIn) ?
std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().top, r.gapsIn.value().right, r.gapsIn.value().bottom, r.gapsIn.value().left) : std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().m_top, r.gapsIn.value().m_right, r.gapsIn.value().m_bottom, r.gapsIn.value().m_left) :
""; "";
const std::string gapsOut = (bool)(r.gapsOut) ? const std::string gapsOut = (bool)(r.gapsOut) ?
std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) : std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().m_top, r.gapsOut.value().m_right, r.gapsOut.value().m_bottom, r.gapsOut.value().m_left) :
""; "";
const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : ""; const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : "";
const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : ""; const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : "";
@@ -360,15 +388,15 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
return result; return result;
} else { } else {
const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "<unset>" : escapeJSONStrings(r.monitor)); const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "<unset>" : escapeJSONStrings(r.monitor));
const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : "<unset>"); const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : "<unset>");
const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : "<unset>"); const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : "<unset>");
const std::string gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().top), std::to_string(r.gapsIn.value().right), const std::string gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().m_top), std::to_string(r.gapsIn.value().m_right),
std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) : std::to_string(r.gapsIn.value().m_bottom), std::to_string(r.gapsIn.value().m_left)) :
std::format("\tgapsIn: <unset>\n"); std::format("\tgapsIn: <unset>\n");
const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().top), std::to_string(r.gapsOut.value().right), const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().m_top), std::to_string(r.gapsOut.value().m_right),
std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) : std::to_string(r.gapsOut.value().m_bottom), std::to_string(r.gapsOut.value().m_left)) :
std::format("\tgapsOut: <unset>\n"); std::format("\tgapsOut: <unset>\n");
const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>"); const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>");
const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : "<unset>"); const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : "<unset>");
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>"); const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>");
@@ -384,11 +412,11 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
} }
static std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) { static std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_lastMonitor)
return "unsafe state"; return "unsafe state";
std::string result = ""; std::string result = "";
auto w = g_pCompositor->m_pLastMonitor->activeWorkspace; auto w = g_pCompositor->m_lastMonitor->m_activeWorkspace;
if (!valid(w)) if (!valid(w))
return "internal error"; return "internal error";
@@ -401,7 +429,7 @@ static std::string workspacesRequest(eHyprCtlOutputFormat format, std::string re
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto const& w : g_pCompositor->m_vWorkspaces) { for (auto const& w : g_pCompositor->m_workspaces) {
result += CHyprCtl::getWorkspaceData(w, format); result += CHyprCtl::getWorkspaceData(w, format);
result += ","; result += ",";
} }
@@ -409,7 +437,7 @@ static std::string workspacesRequest(eHyprCtlOutputFormat format, std::string re
trimTrailingComma(result); trimTrailingComma(result);
result += "]"; result += "]";
} else { } else {
for (auto const& w : g_pCompositor->m_vWorkspaces) { for (auto const& w : g_pCompositor->m_workspaces) {
result += CHyprCtl::getWorkspaceData(w, format); result += CHyprCtl::getWorkspaceData(w, format);
} }
} }
@@ -438,7 +466,7 @@ static std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::strin
} }
static std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) { static std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) {
const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto PWINDOW = g_pCompositor->m_lastWindow.lock();
if (!validMapped(PWINDOW)) if (!validMapped(PWINDOW))
return format == eHyprCtlOutputFormat::FORMAT_JSON ? "{}" : "Invalid"; return format == eHyprCtlOutputFormat::FORMAT_JSON ? "{}" : "Invalid";
@@ -457,15 +485,15 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n"; result += "{\n";
for (auto const& mon : g_pCompositor->m_vMonitors) { for (auto const& mon : g_pCompositor->m_monitors) {
result += std::format( result += std::format(
R"#("{}": {{ R"#("{}": {{
"levels": {{ "levels": {{
)#", )#",
escapeJSONStrings(mon->szName)); escapeJSONStrings(mon->m_name));
int layerLevel = 0; int layerLevel = 0;
for (auto const& level : mon->m_aLayerSurfaceLayers) { for (auto const& level : mon->m_layerSurfaceLayers) {
result += std::format( result += std::format(
R"#( R"#(
"{}": [ "{}": [
@@ -482,7 +510,7 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
"namespace": "{}", "namespace": "{}",
"pid": {} "pid": {}
}},)#", }},)#",
(uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, escapeJSONStrings(layer->szNamespace), (uintptr_t)layer.get(), layer->m_geometry.x, layer->m_geometry.y, layer->m_geometry.width, layer->m_geometry.height, escapeJSONStrings(layer->m_namespace),
layer->getPID()); layer->getPID());
} }
@@ -506,16 +534,16 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques
result += "\n}\n"; result += "\n}\n";
} else { } else {
for (auto const& mon : g_pCompositor->m_vMonitors) { for (auto const& mon : g_pCompositor->m_monitors) {
result += std::format("Monitor {}:\n", mon->szName); result += std::format("Monitor {}:\n", mon->m_name);
int layerLevel = 0; int layerLevel = 0;
static const std::array<std::string, 4> levelNames = {"background", "bottom", "top", "overlay"}; static const std::array<std::string, 4> levelNames = {"background", "bottom", "top", "overlay"};
for (auto const& level : mon->m_aLayerSurfaceLayers) { for (auto const& level : mon->m_layerSurfaceLayers) {
result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]); result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]);
for (auto const& layer : level) { for (auto const& layer : level) {
result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}, pid: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}, pid: {}\n", (uintptr_t)layer.get(), layer->m_geometry.x, layer->m_geometry.y,
layer->geometry.width, layer->geometry.height, layer->szNamespace, layer->getPID()); layer->m_geometry.width, layer->m_geometry.height, layer->m_namespace, layer->getPID());
} }
layerLevel++; layerLevel++;
@@ -576,26 +604,26 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
std::string result = ""; std::string result = "";
auto getModState = [](SP<IKeyboard> keyboard, const char* xkbModName) -> bool { auto getModState = [](SP<IKeyboard> keyboard, const char* xkbModName) -> bool {
auto IDX = xkb_keymap_mod_get_index(keyboard->xkbKeymap, xkbModName); auto IDX = xkb_keymap_mod_get_index(keyboard->m_xkbKeymap, xkbModName);
if (IDX == XKB_MOD_INVALID) if (IDX == XKB_MOD_INVALID)
return false; return false;
return (keyboard->modifiersState.locked & (1 << IDX)) > 0; return (keyboard->m_modifiersState.locked & (1 << IDX)) > 0;
}; };
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "{\n"; result += "{\n";
result += "\"mice\": [\n"; result += "\"mice\": [\n";
for (auto const& m : g_pInputManager->m_vPointers) { for (auto const& m : g_pInputManager->m_pointers) {
result += std::format( result += std::format(
R"#( {{ R"#( {{
"address": "0x{:x}", "address": "0x{:x}",
"name": "{}", "name": "{}",
"defaultSpeed": {:.5f} "defaultSpeed": {:.5f}
}},)#", }},)#",
(uintptr_t)m.get(), escapeJSONStrings(m->hlName), (uintptr_t)m.get(), escapeJSONStrings(m->m_hlName),
m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f); m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f);
} }
@@ -603,7 +631,7 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
result += "\n],\n"; result += "\n],\n";
result += "\"keyboards\": [\n"; result += "\"keyboards\": [\n";
for (auto const& k : g_pInputManager->m_vKeyboards) { for (auto const& k : g_pInputManager->m_keyboards) {
const auto KM = k->getActiveLayout(); const auto KM = k->getActiveLayout();
result += std::format( result += std::format(
R"#( {{ R"#( {{
@@ -619,9 +647,9 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
"numLock": {}, "numLock": {},
"main": {} "main": {}
}},)#", }},)#",
(uintptr_t)k.get(), escapeJSONStrings(k->hlName), escapeJSONStrings(k->currentRules.rules), escapeJSONStrings(k->currentRules.model), (uintptr_t)k.get(), escapeJSONStrings(k->m_hlName), escapeJSONStrings(k->m_currentRules.rules), escapeJSONStrings(k->m_currentRules.model),
escapeJSONStrings(k->currentRules.layout), escapeJSONStrings(k->currentRules.variant), escapeJSONStrings(k->currentRules.options), escapeJSONStrings(KM), escapeJSONStrings(k->m_currentRules.layout), escapeJSONStrings(k->m_currentRules.variant), escapeJSONStrings(k->m_currentRules.options), escapeJSONStrings(KM),
(getModState(k, XKB_MOD_NAME_CAPS) ? "true" : "false"), (getModState(k, XKB_MOD_NAME_NUM) ? "true" : "false"), (k->active ? "true" : "false")); (getModState(k, XKB_MOD_NAME_CAPS) ? "true" : "false"), (getModState(k, XKB_MOD_NAME_NUM) ? "true" : "false"), (k->m_active ? "true" : "false"));
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -629,7 +657,7 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
result += "\"tablets\": [\n"; result += "\"tablets\": [\n";
for (auto const& d : g_pInputManager->m_vTabletPads) { for (auto const& d : g_pInputManager->m_tabletPads) {
result += std::format( result += std::format(
R"#( {{ R"#( {{
"address": "0x{:x}", "address": "0x{:x}",
@@ -639,19 +667,19 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
"name": "{}" "name": "{}"
}} }}
}},)#", }},)#",
(uintptr_t)d.get(), (uintptr_t)d->parent.get(), escapeJSONStrings(d->parent ? d->parent->hlName : "")); (uintptr_t)d.get(), (uintptr_t)d->m_parent.get(), escapeJSONStrings(d->m_parent ? d->m_parent->m_hlName : ""));
} }
for (auto const& d : g_pInputManager->m_vTablets) { for (auto const& d : g_pInputManager->m_tablets) {
result += std::format( result += std::format(
R"#( {{ R"#( {{
"address": "0x{:x}", "address": "0x{:x}",
"name": "{}" "name": "{}"
}},)#", }},)#",
(uintptr_t)d.get(), escapeJSONStrings(d->hlName)); (uintptr_t)d.get(), escapeJSONStrings(d->m_hlName));
} }
for (auto const& d : g_pInputManager->m_vTabletTools) { for (auto const& d : g_pInputManager->m_tabletTools) {
result += std::format( result += std::format(
R"#( {{ R"#( {{
"address": "0x{:x}", "address": "0x{:x}",
@@ -665,13 +693,13 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
result += "\"touch\": [\n"; result += "\"touch\": [\n";
for (auto const& d : g_pInputManager->m_vTouches) { for (auto const& d : g_pInputManager->m_touches) {
result += std::format( result += std::format(
R"#( {{ R"#( {{
"address": "0x{:x}", "address": "0x{:x}",
"name": "{}" "name": "{}"
}},)#", }},)#",
(uintptr_t)d.get(), escapeJSONStrings(d->hlName)); (uintptr_t)d.get(), escapeJSONStrings(d->m_hlName));
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -679,7 +707,7 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
result += "\"switches\": [\n"; result += "\"switches\": [\n";
for (auto const& d : g_pInputManager->m_lSwitches) { for (auto const& d : g_pInputManager->m_switches) {
result += std::format( result += std::format(
R"#( {{ R"#( {{
"address": "0x{:x}", "address": "0x{:x}",
@@ -696,45 +724,45 @@ static std::string devicesRequest(eHyprCtlOutputFormat format, std::string reque
} else { } else {
result += "mice:\n"; result += "mice:\n";
for (auto const& m : g_pInputManager->m_vPointers) { for (auto const& m : g_pInputManager->m_pointers) {
result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", (uintptr_t)m.get(), m->hlName, result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", (uintptr_t)m.get(), m->m_hlName,
(m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f)); (m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f));
} }
result += "\n\nKeyboards:\n"; result += "\n\nKeyboards:\n";
for (auto const& k : g_pInputManager->m_vKeyboards) { for (auto const& k : g_pInputManager->m_keyboards) {
const auto KM = k->getActiveLayout(); const auto KM = k->getActiveLayout();
result += result += std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tcapsLock: "
std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tcapsLock: " "{}\n\t\t\tnumLock: {}\n\t\t\tmain: {}\n",
"{}\n\t\t\tnumLock: {}\n\t\t\tmain: {}\n", (uintptr_t)k.get(), k->m_hlName, k->m_currentRules.rules, k->m_currentRules.model, k->m_currentRules.layout, k->m_currentRules.variant,
(uintptr_t)k.get(), k->hlName, k->currentRules.rules, k->currentRules.model, k->currentRules.layout, k->currentRules.variant, k->currentRules.options, k->m_currentRules.options, KM, (getModState(k, XKB_MOD_NAME_CAPS) ? "yes" : "no"), (getModState(k, XKB_MOD_NAME_NUM) ? "yes" : "no"),
KM, (getModState(k, XKB_MOD_NAME_CAPS) ? "yes" : "no"), (getModState(k, XKB_MOD_NAME_NUM) ? "yes" : "no"), (k->active ? "yes" : "no")); (k->m_active ? "yes" : "no"));
} }
result += "\n\nTablets:\n"; result += "\n\nTablets:\n";
for (auto const& d : g_pInputManager->m_vTabletPads) { for (auto const& d : g_pInputManager->m_tabletPads) {
result += std::format("\tTablet Pad at {:x} (belongs to {:x} -> {})\n", (uintptr_t)d.get(), (uintptr_t)d->parent.get(), d->parent ? d->parent->hlName : ""); result += std::format("\tTablet Pad at {:x} (belongs to {:x} -> {})\n", (uintptr_t)d.get(), (uintptr_t)d->m_parent.get(), d->m_parent ? d->m_parent->m_hlName : "");
} }
for (auto const& d : g_pInputManager->m_vTablets) { for (auto const& d : g_pInputManager->m_tablets) {
result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->aq()->physicalSize.x, d->aq()->physicalSize.y); result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->m_hlName, d->aq()->physicalSize.x, d->aq()->physicalSize.y);
} }
for (auto const& d : g_pInputManager->m_vTabletTools) { for (auto const& d : g_pInputManager->m_tabletTools) {
result += std::format("\tTablet Tool at {:x}\n", (uintptr_t)d.get()); result += std::format("\tTablet Tool at {:x}\n", (uintptr_t)d.get());
} }
result += "\n\nTouch:\n"; result += "\n\nTouch:\n";
for (auto const& d : g_pInputManager->m_vTouches) { for (auto const& d : g_pInputManager->m_touches) {
result += std::format("\tTouch Device at {:x}:\n\t\t{}\n", (uintptr_t)d.get(), d->hlName); result += std::format("\tTouch Device at {:x}:\n\t\t{}\n", (uintptr_t)d.get(), d->m_hlName);
} }
result += "\n\nSwitches:\n"; result += "\n\nSwitches:\n";
for (auto const& d : g_pInputManager->m_lSwitches) { for (auto const& d : g_pInputManager->m_switches) {
result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pDevice ? d.pDevice->getName() : ""); result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pDevice ? d.pDevice->getName() : "");
} }
} }
@@ -800,10 +828,10 @@ static std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string re
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[\n\"log\":\""; result += "[\n\"log\":\"";
result += escapeJSONStrings(Debug::rollingLog); result += escapeJSONStrings(Debug::m_rollingLog);
result += "\"]"; result += "\"]";
} else { } else {
result = Debug::rollingLog; result = Debug::m_rollingLog;
} }
return result; return result;
@@ -838,7 +866,7 @@ static std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::stri
static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = ""; std::string ret = "";
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto const& kb : g_pKeybindManager->m_vKeybinds) { for (auto const& kb : g_pKeybindManager->m_keybinds) {
ret += "bind"; ret += "bind";
if (kb->locked) if (kb->locked)
ret += "l"; ret += "l";
@@ -859,7 +887,7 @@ static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request
} else { } else {
// json // json
ret += "["; ret += "[";
for (auto const& kb : g_pKeybindManager->m_vKeybinds) { for (auto const& kb : g_pKeybindManager->m_keybinds) {
ret += std::format( ret += std::format(
R"#( R"#(
{{ {{
@@ -1024,12 +1052,12 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
result += "plugins:\n"; result += "plugins:\n";
if (g_pPluginSystem) { if (g_pPluginSystem) {
for (auto const& pl : g_pPluginSystem->getAllPlugins()) { for (auto const& pl : g_pPluginSystem->getAllPlugins()) {
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); result += std::format(" {} by {} ver {}\n", pl->m_name, pl->m_author, pl->m_version);
} }
} else } else
result += "\tunknown: not runtime\n"; result += "\tunknown: not runtime\n";
if (g_pHyprCtl && g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { if (g_pHyprCtl && g_pHyprCtl->m_currentRequestParams.sysInfoConfig) {
result += "\n======Config-Start======\n"; result += "\n======Config-Start======\n";
result += g_pConfigManager->getConfigString(); result += g_pConfigManager->getConfigString();
result += "\n======Config-End========\n"; result += "\n======Config-End========\n";
@@ -1048,8 +1076,8 @@ static std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in)
if ((int)in.find_first_of(' ') != -1) if ((int)in.find_first_of(' ') != -1)
DISPATCHARG = in.substr(in.find_first_of(' ') + 1); DISPATCHARG = in.substr(in.find_first_of(' ') + 1);
const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(DISPATCHSTR); const auto DISPATCHER = g_pKeybindManager->m_dispatchers.find(DISPATCHSTR);
if (DISPATCHER == g_pKeybindManager->m_mDispatchers.end()) if (DISPATCHER == g_pKeybindManager->m_dispatchers.end())
return "Invalid dispatcher"; return "Invalid dispatcher";
SDispatchResult res = DISPATCHER->second(DISPATCHARG); SDispatchResult res = DISPATCHER->second(DISPATCHARG);
@@ -1085,7 +1113,7 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in)
// if we are executing a dynamic source we have to reload everything, so every if will have a check for source. // if we are executing a dynamic source we have to reload everything, so every if will have a check for source.
if (COMMAND == "monitor" || COMMAND == "source") if (COMMAND == "monitor" || COMMAND == "source")
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords g_pConfigManager->m_wantsMonitorReload = true; // for monitor keywords
if (COMMAND.contains("input") || COMMAND.contains("device") || COMMAND == "source") { if (COMMAND.contains("input") || COMMAND.contains("device") || COMMAND == "source") {
g_pInputManager->setKeyboardLayout(); // update kb layout g_pInputManager->setKeyboardLayout(); // update kb layout
@@ -1100,10 +1128,10 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in)
g_pLayoutManager->switchToLayout(*PLAYOUT); // update layout g_pLayoutManager->switchToLayout(*PLAYOUT); // update layout
if (COMMAND.contains("decoration:screen_shader") || COMMAND == "source") if (COMMAND.contains("decoration:screen_shader") || COMMAND == "source")
g_pHyprOpenGL->m_bReloadScreenShader = true; g_pHyprOpenGL->m_reloadScreenShader = true;
if (COMMAND.contains("blur") || COMMAND == "source") { if (COMMAND.contains("blur") || COMMAND == "source") {
for (auto& [m, rd] : g_pHyprOpenGL->m_mMonitorRenderResources) { for (auto& [m, rd] : g_pHyprOpenGL->m_monitorRenderResources) {
rd.blurFBDirty = true; rd.blurFBDirty = true;
} }
} }
@@ -1114,9 +1142,9 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in)
// decorations will probably need a repaint // decorations will probably need a repaint
if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source" || if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source" ||
COMMAND.starts_with("windowrule")) { COMMAND.starts_with("windowrule")) {
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_monitors) {
g_pHyprRenderer->damageMonitor(m); g_pHyprRenderer->damageMonitor(m);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->m_id);
} }
} }
@@ -1133,7 +1161,7 @@ static std::string reloadRequest(eHyprCtlOutputFormat format, std::string reques
const auto REQMODE = request.substr(request.find_last_of(' ') + 1); const auto REQMODE = request.substr(request.find_last_of(' ') + 1);
if (REQMODE == "config-only") if (REQMODE == "config-only")
g_pConfigManager->m_bNoMonitorReload = true; g_pConfigManager->m_noMonitorReload = true;
g_pConfigManager->reload(); g_pConfigManager->reload();
@@ -1147,7 +1175,7 @@ static std::string killRequest(eHyprCtlOutputFormat format, std::string request)
} }
static std::string splashRequest(eHyprCtlOutputFormat format, std::string request) { static std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
return g_pCompositor->m_szCurrentSplash; return g_pCompositor->m_currentSplash;
} }
static std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) { static std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) {
@@ -1227,19 +1255,20 @@ static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::stri
SP<IKeyboard> pKeyboard; SP<IKeyboard> pKeyboard;
auto updateKeyboard = [](const SP<IKeyboard> KEEB, const std::string& CMD) -> std::optional<std::string> { auto updateKeyboard = [](const SP<IKeyboard> KEEB, const std::string& CMD) -> std::optional<std::string> {
const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap); const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->m_xkbKeymap);
xkb_layout_index_t activeLayout = 0; xkb_layout_index_t activeLayout = 0;
while (activeLayout < LAYOUTS) { while (activeLayout < LAYOUTS) {
if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) if (xkb_state_layout_index_is_active(KEEB->m_xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1)
break; break;
activeLayout++; activeLayout++;
} }
if (CMD == "next") if (CMD == "next")
KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1); KEEB->updateModifiers(KEEB->m_modifiersState.depressed, KEEB->m_modifiersState.latched, KEEB->m_modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1);
else if (CMD == "prev") else if (CMD == "prev")
KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1); KEEB->updateModifiers(KEEB->m_modifiersState.depressed, KEEB->m_modifiersState.latched, KEEB->m_modifiersState.locked,
activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
else { else {
int requestedLayout = 0; int requestedLayout = 0;
try { try {
@@ -1250,15 +1279,15 @@ static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::stri
return "layout idx out of range of " + std::to_string(LAYOUTS); return "layout idx out of range of " + std::to_string(LAYOUTS);
} }
KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout); KEEB->updateModifiers(KEEB->m_modifiersState.depressed, KEEB->m_modifiersState.latched, KEEB->m_modifiersState.locked, requestedLayout);
} }
return std::nullopt; return std::nullopt;
}; };
if (KB == "main" || KB == "active" || KB == "current") { if (KB == "main" || KB == "active" || KB == "current") {
for (auto const& k : g_pInputManager->m_vKeyboards) { for (auto const& k : g_pInputManager->m_keyboards) {
if (!k->active) if (!k->m_active)
continue; continue;
pKeyboard = k; pKeyboard = k;
@@ -1266,17 +1295,17 @@ static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::stri
} }
} else if (KB == "all") { } else if (KB == "all") {
std::string result = ""; std::string result = "";
for (auto const& k : g_pInputManager->m_vKeyboards) { for (auto const& k : g_pInputManager->m_keyboards) {
auto res = updateKeyboard(k, CMD); auto res = updateKeyboard(k, CMD);
if (res.has_value()) if (res.has_value())
result += *res + "\n"; result += *res + "\n";
} }
return result.empty() ? "ok" : result; return result.empty() ? "ok" : result;
} else { } else {
auto k = std::find_if(g_pInputManager->m_vKeyboards.begin(), g_pInputManager->m_vKeyboards.end(), auto k = std::find_if(g_pInputManager->m_keyboards.begin(), g_pInputManager->m_keyboards.end(),
[&](const auto& other) { return other->hlName == g_pInputManager->deviceNameToInternalString(KB); }); [&](const auto& other) { return other->m_hlName == g_pInputManager->deviceNameToInternalString(KB); });
if (k == g_pInputManager->m_vKeyboards.end()) if (k == g_pInputManager->m_keyboards.end())
return "device not found"; return "device not found";
pKeyboard = *k; pKeyboard = *k;
@@ -1323,7 +1352,7 @@ static std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string req
} }
static std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) { static std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
auto result = g_pKeybindManager->m_mDispatchers["setprop"](request.substr(request.find_first_of(' ') + 1)); auto result = g_pKeybindManager->m_dispatchers["setprop"](request.substr(request.find_first_of(' ') + 1));
return "DEPRECATED: use hyprctl dispatch setprop instead" + (result.success ? "" : "\n" + result.error); return "DEPRECATED: use hyprctl dispatch setprop instead" + (result.success ? "" : "\n" + result.error);
} }
@@ -1393,7 +1422,7 @@ static std::string decorationRequest(eHyprCtlOutputFormat format, std::string re
std::string result = ""; std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto const& wd : PWINDOW->m_dWindowDecorations) { for (auto const& wd : PWINDOW->m_windowDecorations) {
result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},"; result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},";
} }
@@ -1401,7 +1430,7 @@ static std::string decorationRequest(eHyprCtlOutputFormat format, std::string re
result += "]"; result += "]";
} else { } else {
result = +"Decoration\tPriority\n"; result = +"Decoration\tPriority\n";
for (auto const& wd : PWINDOW->m_dWindowDecorations) { for (auto const& wd : PWINDOW->m_windowDecorations) {
result += wd->getDisplayName() + "\t" + std::to_string(wd->getPositioningInfo().priority) + "\n"; result += wd->getDisplayName() + "\t" + std::to_string(wd->getPositioningInfo().priority) + "\n";
} }
} }
@@ -1420,8 +1449,8 @@ static std::string dispatchOutput(eHyprCtlOutputFormat format, std::string reque
bool added = false; bool added = false;
if (!vars[3].empty()) { if (!vars[3].empty()) {
for (auto const& m : g_pCompositor->m_vRealMonitors) { for (auto const& m : g_pCompositor->m_realMonitors) {
if (m->szName == vars[3]) if (m->m_name == vars[3])
return "Name already taken"; return "Name already taken";
} }
} }
@@ -1430,7 +1459,7 @@ static std::string dispatchOutput(eHyprCtlOutputFormat format, std::string reque
if (g_pCompositor->getMonitorFromName(vars[3])) if (g_pCompositor->getMonitorFromName(vars[3]))
return "A real monitor already uses that name."; return "A real monitor already uses that name.";
for (auto const& impl : g_pCompositor->m_pAqBackend->getImplementations() | std::views::reverse) { for (auto const& impl : g_pCompositor->m_aqBackend->getImplementations() | std::views::reverse) {
auto type = impl->type(); auto type = impl->type();
if (type == Aquamarine::AQ_BACKEND_HEADLESS && (vars[2] == "headless" || vars[2] == "auto")) { if (type == Aquamarine::AQ_BACKEND_HEADLESS && (vars[2] == "headless" || vars[2] == "auto")) {
@@ -1455,10 +1484,10 @@ static std::string dispatchOutput(eHyprCtlOutputFormat format, std::string reque
if (!PMONITOR) if (!PMONITOR)
return "output not found"; return "output not found";
if (!PMONITOR->createdByUser) if (!PMONITOR->m_createdByUser)
return "cannot remove a real display. Use the monitor keyword."; return "cannot remove a real display. Use the monitor keyword.";
PMONITOR->output->destroy(); PMONITOR->m_output->destroy();
} }
return "ok"; return "ok";
@@ -1477,10 +1506,18 @@ static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string reque
if (vars.size() < 3) if (vars.size() < 3)
return "not enough args"; return "not enough args";
const auto PLUGIN = g_pPluginSystem->loadPlugin(PATH); g_pHyprCtl->m_currentRequestParams.pendingPromise = CPromise<std::string>::make([PATH](SP<CPromiseResolver<std::string>> resolver) {
g_pPluginSystem->loadPlugin(PATH)->then([resolver, PATH](SP<CPromiseResult<CPlugin*>> result) {
if (result->hasError()) {
resolver->reject(result->error());
return;
}
if (!PLUGIN) resolver->resolve("ok");
return "error in loading plugin, last error: " + g_pPluginSystem->m_szLastError; });
});
return "ok";
} else if (OPERATION == "unload") { } else if (OPERATION == "unload") {
if (vars.size() < 3) if (vars.size() < 3)
return "not enough args"; return "not enough args";
@@ -1511,7 +1548,7 @@ static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string reque
"version": "{}", "version": "{}",
"description": "{}" "description": "{}"
}},)#", }},)#",
escapeJSONStrings(p->name), escapeJSONStrings(p->author), (uintptr_t)p->m_pHandle, escapeJSONStrings(p->version), escapeJSONStrings(p->description)); escapeJSONStrings(p->m_name), escapeJSONStrings(p->m_author), (uintptr_t)p->m_handle, escapeJSONStrings(p->m_version), escapeJSONStrings(p->m_description));
} }
trimTrailingComma(result); trimTrailingComma(result);
result += "]"; result += "]";
@@ -1520,8 +1557,8 @@ static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string reque
return "no plugins loaded"; return "no plugins loaded";
for (auto const& p : PLUGINS) { for (auto const& p : PLUGINS) {
result += result += std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->m_name, p->m_author, (uintptr_t)p->m_handle, p->m_version,
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); p->m_description);
} }
} }
@@ -1643,6 +1680,13 @@ static std::string submapRequest(eHyprCtlOutputFormat format, std::string reques
return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n"); return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n");
} }
static std::string reloadShaders(eHyprCtlOutputFormat format, std::string request) {
if (g_pHyprOpenGL->initShaders())
return format == FORMAT_JSON ? "{\"ok\": true}" : "ok";
else
return format == FORMAT_JSON ? "{\"ok\": false}" : "error";
}
CHyprCtl::CHyprCtl() { CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
@@ -1665,6 +1709,7 @@ CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions}); registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
registerCommand(SHyprCtlCommand{"submap", true, submapRequest}); registerCommand(SHyprCtlCommand{"submap", true, submapRequest});
registerCommand(SHyprCtlCommand{.name = "reloadshaders", .exact = true, .fn = reloadShaders});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
@@ -1693,17 +1738,18 @@ CHyprCtl::~CHyprCtl() {
} }
SP<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) { SP<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) {
return m_vCommands.emplace_back(makeShared<SHyprCtlCommand>(cmd)); return m_commands.emplace_back(makeShared<SHyprCtlCommand>(cmd));
} }
void CHyprCtl::unregisterCommand(const SP<SHyprCtlCommand>& cmd) { void CHyprCtl::unregisterCommand(const SP<SHyprCtlCommand>& cmd) {
std::erase(m_vCommands, cmd); std::erase(m_commands, cmd);
} }
std::string CHyprCtl::getReply(std::string request) { std::string CHyprCtl::getReply(std::string request) {
auto format = eHyprCtlOutputFormat::FORMAT_NORMAL; auto format = eHyprCtlOutputFormat::FORMAT_NORMAL;
bool reloadAll = false; bool reloadAll = false;
m_sCurrentRequestParams = {}; m_currentRequestParams.all = false;
m_currentRequestParams.sysInfoConfig = false;
// process flags for non-batch requests // process flags for non-batch requests
if (!request.starts_with("[[BATCH]]") && request.contains("/")) { if (!request.starts_with("[[BATCH]]") && request.contains("/")) {
@@ -1727,9 +1773,9 @@ std::string CHyprCtl::getReply(std::string request) {
else if (c == 'r') else if (c == 'r')
reloadAll = true; reloadAll = true;
else if (c == 'a') else if (c == 'a')
m_sCurrentRequestParams.all = true; m_currentRequestParams.all = true;
else if (c == 'c') else if (c == 'c')
m_sCurrentRequestParams.sysInfoConfig = true; m_currentRequestParams.sysInfoConfig = true;
} }
if (sepIndex < request.size()) if (sepIndex < request.size())
@@ -1739,7 +1785,7 @@ std::string CHyprCtl::getReply(std::string request) {
std::string result = ""; std::string result = "";
// parse exact cmds first, then non-exact. // parse exact cmds first, then non-exact.
for (auto const& cmd : m_vCommands) { for (auto const& cmd : m_commands) {
if (!cmd->exact) if (!cmd->exact)
continue; continue;
@@ -1750,7 +1796,7 @@ std::string CHyprCtl::getReply(std::string request) {
} }
if (result.empty()) if (result.empty())
for (auto const& cmd : m_vCommands) { for (auto const& cmd : m_commands) {
if (cmd->exact) if (cmd->exact)
continue; continue;
@@ -1764,7 +1810,7 @@ std::string CHyprCtl::getReply(std::string request) {
return "unknown request"; return "unknown request";
if (reloadAll) { if (reloadAll) {
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords g_pConfigManager->m_wantsMonitorReload = true; // for monitor keywords
g_pInputManager->setKeyboardLayout(); // update kb layout g_pInputManager->setKeyboardLayout(); // update kb layout
g_pInputManager->setPointerConfigs(); // update mouse cfgs g_pInputManager->setPointerConfigs(); // update mouse cfgs
@@ -1775,23 +1821,23 @@ std::string CHyprCtl::getReply(std::string request) {
g_pLayoutManager->switchToLayout(*PLAYOUT); // update layout g_pLayoutManager->switchToLayout(*PLAYOUT); // update layout
g_pHyprOpenGL->m_bReloadScreenShader = true; g_pHyprOpenGL->m_reloadScreenShader = true;
for (auto& [m, rd] : g_pHyprOpenGL->m_mMonitorRenderResources) { for (auto& [m, rd] : g_pHyprOpenGL->m_monitorRenderResources) {
rd.blurFBDirty = true; rd.blurFBDirty = true;
} }
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (!w->m_bIsMapped || !w->m_pWorkspace || !w->m_pWorkspace->isVisible()) if (!w->m_isMapped || !w->m_workspace || !w->m_workspace->isVisible())
continue; continue;
w->updateDynamicRules(); w->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(w); g_pCompositor->updateWindowAnimatedDecorationValues(w);
} }
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_monitors) {
g_pHyprRenderer->damageMonitor(m); g_pHyprRenderer->damageMonitor(m);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->m_id);
} }
} }
@@ -1846,16 +1892,26 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
return 0; return 0;
if (!g_pHyprCtl->m_iSocketFD.isValid()) if (!g_pHyprCtl->m_socketFD.isValid())
return 0; return 0;
sockaddr_in clientAddress; sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress); socklen_t clientSize = sizeof(clientAddress);
const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_socketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
std::array<char, 1024> readBuffer; std::array<char, 1024> readBuffer;
// try to get creds
CRED_T creds;
uint32_t len = sizeof(creds);
if (getsockopt(ACCEPTEDCONNECTION, CRED_LVL, CRED_OPT, &creds, &len) == -1)
Debug::log(ERR, "Hyprctl: failed to get peer creds");
else {
g_pHyprCtl->m_currentRequestParams.pid = creds.CRED_PID;
Debug::log(LOG, "Hyprctl: new connection from pid {}", creds.CRED_PID);
}
// //
pollfd pollfds[1] = { pollfd pollfds[1] = {
{ {
@@ -1892,45 +1948,61 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
reply = "Err: " + std::string(e.what()); reply = "Err: " + std::string(e.what());
} }
successWrite(ACCEPTEDCONNECTION, reply); if (g_pHyprCtl->m_currentRequestParams.pendingPromise) {
// we have a promise pending
g_pHyprCtl->m_currentRequestParams.pendingPromise->then([ACCEPTEDCONNECTION, request](SP<CPromiseResult<std::string>> result) {
const auto RES = result->hasError() ? result->error() : result->result();
successWrite(ACCEPTEDCONNECTION, RES);
if (isFollowUpRollingLogRequest(request)) { // No rollinglog or ensureMonitor here. These are only for plugins for now.
Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket.");
Debug::SRollingLogFollow::get().startFor(ACCEPTEDCONNECTION);
runWritingDebugLogThread(ACCEPTEDCONNECTION);
Debug::log(LOG, Debug::SRollingLogFollow::get().debugInfo());
} else
close(ACCEPTEDCONNECTION);
if (g_pConfigManager->m_bWantsMonitorReload) close(ACCEPTEDCONNECTION);
g_pConfigManager->ensureMonitorStatus(); });
g_pHyprCtl->m_currentRequestParams.pendingPromise.reset();
} else {
successWrite(ACCEPTEDCONNECTION, reply);
if (isFollowUpRollingLogRequest(request)) {
Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket.");
Debug::SRollingLogFollow::get().startFor(ACCEPTEDCONNECTION);
runWritingDebugLogThread(ACCEPTEDCONNECTION);
Debug::log(LOG, Debug::SRollingLogFollow::get().debugInfo());
} else
close(ACCEPTEDCONNECTION);
if (g_pConfigManager->m_wantsMonitorReload)
g_pConfigManager->ensureMonitorStatus();
g_pHyprCtl->m_currentRequestParams.pid = 0;
}
return 0; return 0;
} }
void CHyprCtl::startHyprCtlSocket() { void CHyprCtl::startHyprCtlSocket() {
m_iSocketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)}; m_socketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)};
if (!m_iSocketFD.isValid()) { if (!m_socketFD.isValid()) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
return; return;
} }
sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX};
m_socketPath = g_pCompositor->m_szInstancePath + "/.socket.sock"; m_socketPath = g_pCompositor->m_instancePath + "/.socket.sock";
strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str()); strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str());
if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { if (bind(m_socketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work.");
return; return;
} }
// 10 max queued. // 10 max queued.
listen(m_iSocketFD.get(), 10); listen(m_socketFD.get(), 10);
Debug::log(LOG, "Hypr socket started at {}", m_socketPath); Debug::log(LOG, "Hypr socket started at {}", m_socketPath);
m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr); m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_wlEventLoop, m_socketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
} }

View File

@@ -2,8 +2,10 @@
#include <fstream> #include <fstream>
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#include "../helpers/defer/Promise.hpp"
#include "../desktop/Window.hpp" #include "../desktop/Window.hpp"
#include <functional> #include <functional>
#include <sys/types.h>
#include <hyprutils/os/FileDescriptor.hpp> #include <hyprutils/os/FileDescriptor.hpp>
// exposed for main.cpp // exposed for main.cpp
@@ -20,12 +22,14 @@ class CHyprCtl {
void unregisterCommand(const SP<SHyprCtlCommand>& cmd); void unregisterCommand(const SP<SHyprCtlCommand>& cmd);
std::string getReply(std::string); std::string getReply(std::string);
Hyprutils::OS::CFileDescriptor m_iSocketFD; Hyprutils::OS::CFileDescriptor m_socketFD;
struct { struct {
bool all = false; bool all = false;
bool sysInfoConfig = false; bool sysInfoConfig = false;
} m_sCurrentRequestParams; pid_t pid = 0;
SP<CPromise<std::string>> pendingPromise;
} m_currentRequestParams;
static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format); static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format);
static std::string getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format); static std::string getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format);
@@ -34,7 +38,7 @@ class CHyprCtl {
private: private:
void startHyprCtlSocket(); void startHyprCtlSocket();
std::vector<SP<SHyprCtlCommand>> m_vCommands; std::vector<SP<SHyprCtlCommand>> m_commands;
wl_event_source* m_eventSource = nullptr; wl_event_source* m_eventSource = nullptr;
std::string m_socketPath; std::string m_socketPath;
}; };

View File

@@ -7,7 +7,7 @@
#include "../managers/AnimationManager.hpp" #include "../managers/AnimationManager.hpp"
CHyprDebugOverlay::CHyprDebugOverlay() { CHyprDebugOverlay::CHyprDebugOverlay() {
m_pTexture = makeShared<CTexture>(); m_texture = makeShared<CTexture>();
} }
void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
@@ -16,13 +16,13 @@ void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs)
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_dLastRenderTimes.emplace_back(durationUs / 1000.f); m_lastRenderTimes.emplace_back(durationUs / 1000.f);
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate) if (m_lastRenderTimes.size() > (long unsigned int)pMonitor->m_refreshRate)
m_dLastRenderTimes.pop_front(); m_lastRenderTimes.pop_front();
if (!m_pMonitor) if (!m_monitor)
m_pMonitor = pMonitor; m_monitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
@@ -31,13 +31,13 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float du
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_dLastRenderTimesNoOverlay.emplace_back(durationUs / 1000.f); m_lastRenderTimesNoOverlay.emplace_back(durationUs / 1000.f);
if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate) if (m_lastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->m_refreshRate)
m_dLastRenderTimesNoOverlay.pop_front(); m_lastRenderTimesNoOverlay.pop_front();
if (!m_pMonitor) if (!m_monitor)
m_pMonitor = pMonitor; m_monitor = pMonitor;
} }
void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) { void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
@@ -46,36 +46,36 @@ void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) {
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_dLastFrametimes.emplace_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f); m_lastFrametimes.emplace_back(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - m_lastFrame).count() / 1000.f);
if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate) if (m_lastFrametimes.size() > (long unsigned int)pMonitor->m_refreshRate)
m_dLastFrametimes.pop_front(); m_lastFrametimes.pop_front();
m_tpLastFrame = std::chrono::high_resolution_clock::now(); m_lastFrame = std::chrono::high_resolution_clock::now();
if (!m_pMonitor) if (!m_monitor)
m_pMonitor = pMonitor; m_monitor = pMonitor;
// anim data too // anim data too
const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor.lock() : g_pCompositor->m_pLastMonitor.lock(); const auto PMONITORFORTICKS = g_pHyprRenderer->m_mostHzMonitor ? g_pHyprRenderer->m_mostHzMonitor.lock() : g_pCompositor->m_lastMonitor.lock();
if (PMONITORFORTICKS) { if (PMONITORFORTICKS) {
if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate) if (m_lastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->m_refreshRate)
m_dLastAnimationTicks.pop_front(); m_lastAnimationTicks.pop_front();
m_dLastAnimationTicks.push_back(g_pAnimationManager->m_fLastTickTime); m_lastAnimationTicks.push_back(g_pAnimationManager->m_lastTickTimeMs);
} }
} }
int CHyprMonitorDebugOverlay::draw(int offset) { int CHyprMonitorDebugOverlay::draw(int offset) {
if (!m_pMonitor) if (!m_monitor)
return 0; return 0;
// get avg fps // get avg fps
float avgFrametime = 0; float avgFrametime = 0;
float maxFrametime = 0; float maxFrametime = 0;
float minFrametime = 9999; float minFrametime = 9999;
for (auto const& ft : m_dLastFrametimes) { for (auto const& ft : m_lastFrametimes) {
if (ft > maxFrametime) if (ft > maxFrametime)
maxFrametime = ft; maxFrametime = ft;
if (ft < minFrametime) if (ft < minFrametime)
@@ -83,12 +83,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
avgFrametime += ft; avgFrametime += ft;
} }
float varFrametime = maxFrametime - minFrametime; float varFrametime = maxFrametime - minFrametime;
avgFrametime /= m_dLastFrametimes.size() == 0 ? 1 : m_dLastFrametimes.size(); avgFrametime /= m_lastFrametimes.size() == 0 ? 1 : m_lastFrametimes.size();
float avgRenderTime = 0; float avgRenderTime = 0;
float maxRenderTime = 0; float maxRenderTime = 0;
float minRenderTime = 9999; float minRenderTime = 9999;
for (auto const& rt : m_dLastRenderTimes) { for (auto const& rt : m_lastRenderTimes) {
if (rt > maxRenderTime) if (rt > maxRenderTime)
maxRenderTime = rt; maxRenderTime = rt;
if (rt < minRenderTime) if (rt < minRenderTime)
@@ -96,12 +96,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
avgRenderTime += rt; avgRenderTime += rt;
} }
float varRenderTime = maxRenderTime - minRenderTime; float varRenderTime = maxRenderTime - minRenderTime;
avgRenderTime /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size(); avgRenderTime /= m_lastRenderTimes.size() == 0 ? 1 : m_lastRenderTimes.size();
float avgRenderTimeNoOverlay = 0; float avgRenderTimeNoOverlay = 0;
float maxRenderTimeNoOverlay = 0; float maxRenderTimeNoOverlay = 0;
float minRenderTimeNoOverlay = 9999; float minRenderTimeNoOverlay = 9999;
for (auto const& rt : m_dLastRenderTimesNoOverlay) { for (auto const& rt : m_lastRenderTimesNoOverlay) {
if (rt > maxRenderTimeNoOverlay) if (rt > maxRenderTimeNoOverlay)
maxRenderTimeNoOverlay = rt; maxRenderTimeNoOverlay = rt;
if (rt < minRenderTimeNoOverlay) if (rt < minRenderTimeNoOverlay)
@@ -109,12 +109,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
avgRenderTimeNoOverlay += rt; avgRenderTimeNoOverlay += rt;
} }
float varRenderTimeNoOverlay = maxRenderTimeNoOverlay - minRenderTimeNoOverlay; float varRenderTimeNoOverlay = maxRenderTimeNoOverlay - minRenderTimeNoOverlay;
avgRenderTimeNoOverlay /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size(); avgRenderTimeNoOverlay /= m_lastRenderTimes.size() == 0 ? 1 : m_lastRenderTimes.size();
float avgAnimMgrTick = 0; float avgAnimMgrTick = 0;
float maxAnimMgrTick = 0; float maxAnimMgrTick = 0;
float minAnimMgrTick = 9999; float minAnimMgrTick = 9999;
for (auto const& at : m_dLastAnimationTicks) { for (auto const& at : m_lastAnimationTicks) {
if (at > maxAnimMgrTick) if (at > maxAnimMgrTick)
maxAnimMgrTick = at; maxAnimMgrTick = at;
if (at < minAnimMgrTick) if (at < minAnimMgrTick)
@@ -122,13 +122,13 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
avgAnimMgrTick += at; avgAnimMgrTick += at;
} }
float varAnimMgrTick = maxAnimMgrTick - minAnimMgrTick; float varAnimMgrTick = maxAnimMgrTick - minAnimMgrTick;
avgAnimMgrTick /= m_dLastAnimationTicks.size() == 0 ? 1 : m_dLastAnimationTicks.size(); avgAnimMgrTick /= m_lastAnimationTicks.size() == 0 ? 1 : m_lastAnimationTicks.size();
const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms
const float idealFPS = m_dLastFrametimes.size(); const float idealFPS = m_lastFrametimes.size();
static auto fontFamily = CConfigValue<std::string>("misc:font_family"); static auto fontFamily = CConfigValue<std::string>("misc:font_family");
PangoLayout* layoutText = pango_cairo_create_layout(g_pDebugOverlay->m_pCairo); PangoLayout* layoutText = pango_cairo_create_layout(g_pDebugOverlay->m_cairo);
PangoFontDescription* pangoFD = pango_font_description_new(); PangoFontDescription* pangoFD = pango_font_description_new();
pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); pango_font_description_set_family(pangoFD, (*fontFamily).c_str());
@@ -137,7 +137,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float maxTextW = 0; float maxTextW = 0;
int fontSize = 0; int fontSize = 0;
auto cr = g_pDebugOverlay->m_pCairo; auto cr = g_pDebugOverlay->m_cairo;
auto showText = [cr, layoutText, pangoFD, &maxTextW, &fontSize](const char* text, int size) { auto showText = [cr, layoutText, pangoFD, &maxTextW, &fontSize](const char* text, int size) {
if (fontSize != size) { if (fontSize != size) {
@@ -163,22 +163,22 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
const int MARGIN_TOP = 8; const int MARGIN_TOP = 8;
const int MARGIN_LEFT = 4; const int MARGIN_LEFT = 4;
cairo_move_to(cr, MARGIN_LEFT, MARGIN_TOP + offset); cairo_move_to(cr, MARGIN_LEFT, MARGIN_TOP + offset);
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 1.f, 1.f, 1.f, 1.f);
std::string text; std::string text;
showText(m_pMonitor->szName.c_str(), 10); showText(m_monitor->m_name.c_str(), 10);
if (FPS > idealFPS * 0.95f) if (FPS > idealFPS * 0.95f)
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 0.2f, 1.f, 0.2f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 0.2f, 1.f, 0.2f, 1.f);
else if (FPS > idealFPS * 0.8f) else if (FPS > idealFPS * 0.8f)
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 0.2f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 1.f, 1.f, 0.2f, 1.f);
else else
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 0.2f, 0.2f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 1.f, 0.2f, 0.2f, 1.f);
text = std::format("{} FPS", (int)FPS); text = std::format("{} FPS", (int)FPS);
showText(text.c_str(), 16); showText(text.c_str(), 16);
cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f); cairo_set_source_rgba(g_pDebugOverlay->m_cairo, 1.f, 1.f, 1.f, 1.f);
text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime); text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime);
showText(text.c_str(), 10); showText(text.c_str(), 10);
@@ -198,10 +198,10 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
double posX = 0, posY = 0; double posX = 0, posY = 0;
cairo_get_current_point(cr, &posX, &posY); cairo_get_current_point(cr, &posX, &posY);
g_pHyprRenderer->damageBox(m_wbLastDrawnBox); g_pHyprRenderer->damageBox(m_lastDrawnBox);
m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset + MARGIN_TOP - 1, m_lastDrawnBox = {(int)g_pCompositor->m_monitors.front()->m_position.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_monitors.front()->m_position.y + offset + MARGIN_TOP - 1,
(int)maxTextW + 2, posY - offset - MARGIN_TOP + 2}; (int)maxTextW + 2, posY - offset - MARGIN_TOP + 2};
g_pHyprRenderer->damageBox(m_wbLastDrawnBox); g_pHyprRenderer->damageBox(m_lastDrawnBox);
return posY - offset; return posY - offset;
} }
@@ -212,7 +212,7 @@ void CHyprDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) {
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs); m_monitorOverlays[pMonitor].renderData(pMonitor, durationUs);
} }
void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) {
@@ -221,7 +221,7 @@ void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationU
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs); m_monitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
} }
void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) { void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) {
@@ -230,37 +230,37 @@ void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) {
if (!*PDEBUGOVERLAY) if (!*PDEBUGOVERLAY)
return; return;
m_mMonitorOverlays[pMonitor].frameData(pMonitor); m_monitorOverlays[pMonitor].frameData(pMonitor);
} }
void CHyprDebugOverlay::draw() { void CHyprDebugOverlay::draw() {
const auto PMONITOR = g_pCompositor->m_vMonitors.front(); const auto PMONITOR = g_pCompositor->m_monitors.front();
if (!m_pCairoSurface || !m_pCairo) { if (!m_cairoSurface || !m_cairo) {
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); m_cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y);
m_pCairo = cairo_create(m_pCairoSurface); m_cairo = cairo_create(m_cairoSurface);
} }
// clear the pixmap // clear the pixmap
cairo_save(m_pCairo); cairo_save(m_cairo);
cairo_set_operator(m_pCairo, CAIRO_OPERATOR_CLEAR); cairo_set_operator(m_cairo, CAIRO_OPERATOR_CLEAR);
cairo_paint(m_pCairo); cairo_paint(m_cairo);
cairo_restore(m_pCairo); cairo_restore(m_cairo);
// draw the things // draw the things
int offsetY = 0; int offsetY = 0;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_monitors) {
offsetY += m_mMonitorOverlays[m].draw(offsetY); offsetY += m_monitorOverlays[m].draw(offsetY);
offsetY += 5; // for padding between mons offsetY += 5; // for padding between mons
} }
cairo_surface_flush(m_pCairoSurface); cairo_surface_flush(m_cairoSurface);
// copy the data to an OpenGL texture we have // copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(m_pCairoSurface); const auto DATA = cairo_image_surface_get_data(m_cairoSurface);
m_pTexture->allocate(); m_texture->allocate();
glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID); glBindTexture(GL_TEXTURE_2D, m_texture->m_texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -269,10 +269,10 @@ void CHyprDebugOverlay::draw() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
#endif #endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CTexPassElement::SRenderData data; CTexPassElement::SRenderData data;
data.tex = m_pTexture; data.tex = m_texture;
data.box = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; data.box = {0, 0, PMONITOR->m_pixelSize.x, PMONITOR->m_pixelSize.y};
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data)); g_pHyprRenderer->m_renderPass.add(makeShared<CTexPassElement>(data));
} }

View File

@@ -17,13 +17,13 @@ class CHyprMonitorDebugOverlay {
void frameData(PHLMONITOR pMonitor); void frameData(PHLMONITOR pMonitor);
private: private:
std::deque<float> m_dLastFrametimes; std::deque<float> m_lastFrametimes;
std::deque<float> m_dLastRenderTimes; std::deque<float> m_lastRenderTimes;
std::deque<float> m_dLastRenderTimesNoOverlay; std::deque<float> m_lastRenderTimesNoOverlay;
std::deque<float> m_dLastAnimationTicks; std::deque<float> m_lastAnimationTicks;
std::chrono::high_resolution_clock::time_point m_tpLastFrame; std::chrono::high_resolution_clock::time_point m_lastFrame;
PHLMONITORREF m_pMonitor; PHLMONITORREF m_monitor;
CBox m_wbLastDrawnBox; CBox m_lastDrawnBox;
friend class CHyprRenderer; friend class CHyprRenderer;
}; };
@@ -37,12 +37,12 @@ class CHyprDebugOverlay {
void frameData(PHLMONITOR); void frameData(PHLMONITOR);
private: private:
std::map<PHLMONITORREF, CHyprMonitorDebugOverlay> m_mMonitorOverlays; std::map<PHLMONITORREF, CHyprMonitorDebugOverlay> m_monitorOverlays;
cairo_surface_t* m_pCairoSurface = nullptr; cairo_surface_t* m_cairoSurface = nullptr;
cairo_t* m_pCairo = nullptr; cairo_t* m_cairo = nullptr;
SP<CTexture> m_pTexture; SP<CTexture> m_texture;
friend class CHyprMonitorDebugOverlay; friend class CHyprMonitorDebugOverlay;
friend class CHyprRenderer; friend class CHyprRenderer;

View File

@@ -23,24 +23,24 @@ static inline auto iconBackendFromLayout(PangoLayout* layout) {
CHyprNotificationOverlay::CHyprNotificationOverlay() { CHyprNotificationOverlay::CHyprNotificationOverlay() {
static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
if (m_vNotifications.size() == 0) if (m_notifications.size() == 0)
return; return;
g_pHyprRenderer->damageBox(m_bLastDamage); g_pHyprRenderer->damageBox(m_lastDamage);
}); });
m_pTexture = makeShared<CTexture>(); m_texture = makeShared<CTexture>();
} }
CHyprNotificationOverlay::~CHyprNotificationOverlay() { CHyprNotificationOverlay::~CHyprNotificationOverlay() {
if (m_pCairo) if (m_cairo)
cairo_destroy(m_pCairo); cairo_destroy(m_cairo);
if (m_pCairoSurface) if (m_cairoSurface)
cairo_surface_destroy(m_pCairoSurface); cairo_surface_destroy(m_cairoSurface);
} }
void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) { 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(makeUnique<SNotification>()).get(); const auto PNOTIF = m_notifications.emplace_back(makeUnique<SNotification>()).get();
PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text; PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text;
PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color; PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color;
@@ -49,19 +49,19 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CH
PNOTIF->icon = icon; PNOTIF->icon = icon;
PNOTIF->fontSize = fontSize; PNOTIF->fontSize = fontSize;
for (auto const& m : g_pCompositor->m_vMonitors) { for (auto const& m : g_pCompositor->m_monitors) {
g_pCompositor->scheduleFrameForMonitor(m); g_pCompositor->scheduleFrameForMonitor(m);
} }
} }
void CHyprNotificationOverlay::dismissNotifications(const int amount) { void CHyprNotificationOverlay::dismissNotifications(const int amount) {
if (amount == -1) if (amount == -1)
m_vNotifications.clear(); m_notifications.clear();
else { else {
const int AMT = std::min(amount, static_cast<int>(m_vNotifications.size())); const int AMT = std::min(amount, static_cast<int>(m_notifications.size()));
for (int i = 0; i < AMT; ++i) { for (int i = 0; i < AMT; ++i) {
m_vNotifications.erase(m_vNotifications.begin()); m_notifications.erase(m_notifications.begin());
} }
} }
} }
@@ -77,12 +77,12 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
float offsetY = 10; float offsetY = 10;
float maxWidth = 0; float maxWidth = 0;
const auto SCALE = pMonitor->scale; const auto SCALE = pMonitor->m_scale;
const auto MONSIZE = pMonitor->vecTransformedSize; const auto MONSIZE = pMonitor->m_transformedSize;
static auto fontFamily = CConfigValue<std::string>("misc:font_family"); static auto fontFamily = CConfigValue<std::string>("misc:font_family");
PangoLayout* layout = pango_cairo_create_layout(m_pCairo); PangoLayout* layout = pango_cairo_create_layout(m_cairo);
PangoFontDescription* pangoFD = pango_font_description_new(); PangoFontDescription* pangoFD = pango_font_description_new();
pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); pango_font_description_set_family(pangoFD, (*fontFamily).c_str());
@@ -92,9 +92,9 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
const auto iconBackendID = iconBackendFromLayout(layout); const auto iconBackendID = iconBackendFromLayout(layout);
const auto PBEZIER = g_pAnimationManager->getBezier("default"); const auto PBEZIER = g_pAnimationManager->getBezier("default");
for (auto const& notif : m_vNotifications) { for (auto const& notif : m_notifications) {
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; 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); const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->m_pixelSize.x * SCALE) / 1920.f)), 8, 40);
// first rect (bg, col) // first rect (bg, col)
const float FIRSTRECTANIMP = const float FIRSTRECTANIMP =
@@ -139,17 +139,17 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
const auto NOTIFSIZE = Vector2D{textW + 20.0 + iconW + 2 * ICONPADFORNOTIF, textH + 10.0}; const auto NOTIFSIZE = Vector2D{textW + 20.0 + iconW + 2 * ICONPADFORNOTIF, textH + 10.0};
// draw rects // draw rects
cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); cairo_set_source_rgba(m_cairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y); cairo_rectangle(m_cairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y);
cairo_fill(m_pCairo); cairo_fill(m_cairo);
cairo_set_source_rgb(m_pCairo, 0.f, 0.f, 0.f); cairo_set_source_rgb(m_cairo, 0.f, 0.f, 0.f);
cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC, offsetY, NOTIFSIZE.x * SECONDRECTPERC, NOTIFSIZE.y); cairo_rectangle(m_cairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC, offsetY, NOTIFSIZE.x * SECONDRECTPERC, NOTIFSIZE.y);
cairo_fill(m_pCairo); cairo_fill(m_cairo);
cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); cairo_set_source_rgba(m_cairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);
cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2); cairo_rectangle(m_cairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2);
cairo_fill(m_pCairo); cairo_fill(m_cairo);
// draw gradient // draw gradient
if (notif->icon != ICON_NONE) { if (notif->icon != ICON_NONE) {
@@ -158,23 +158,23 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC + GRADIENT_SIZE, offsetY); MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC + GRADIENT_SIZE, offsetY);
cairo_pattern_add_color_stop_rgba(pattern, 0, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, ICONCOLOR.a / 3.0); cairo_pattern_add_color_stop_rgba(pattern, 0, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, ICONCOLOR.a / 3.0);
cairo_pattern_add_color_stop_rgba(pattern, 1, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, 0); cairo_pattern_add_color_stop_rgba(pattern, 1, ICONCOLOR.r, ICONCOLOR.g, ICONCOLOR.b, 0);
cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, GRADIENT_SIZE, NOTIFSIZE.y); cairo_rectangle(m_cairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, GRADIENT_SIZE, NOTIFSIZE.y);
cairo_set_source(m_pCairo, pattern); cairo_set_source(m_cairo, pattern);
cairo_fill(m_pCairo); cairo_fill(m_cairo);
cairo_pattern_destroy(pattern); cairo_pattern_destroy(pattern);
// draw icon // draw icon
cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f); cairo_set_source_rgb(m_cairo, 1.f, 1.f, 1.f);
cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY - 2 + std::round((NOTIFSIZE.y - iconH) / 2.0)); cairo_move_to(m_cairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY - 2 + std::round((NOTIFSIZE.y - iconH) / 2.0));
pango_layout_set_text(layout, ICON.c_str(), -1); pango_layout_set_text(layout, ICON.c_str(), -1);
pango_cairo_show_layout(m_pCairo, layout); pango_cairo_show_layout(m_cairo, layout);
} }
// draw text // draw text
cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f); cairo_set_source_rgb(m_cairo, 1.f, 1.f, 1.f);
cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY - 2 + std::round((NOTIFSIZE.y - textH) / 2.0)); cairo_move_to(m_cairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY - 2 + std::round((NOTIFSIZE.y - textH) / 2.0));
pango_layout_set_text(layout, notif->text.c_str(), -1); pango_layout_set_text(layout, notif->text.c_str(), -1);
pango_cairo_show_layout(m_pCairo, layout); pango_cairo_show_layout(m_cairo, layout);
// adjust offset and move on // adjust offset and move on
offsetY += NOTIFSIZE.y + 10; offsetY += NOTIFSIZE.y + 10;
@@ -187,55 +187,55 @@ CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) {
g_object_unref(layout); g_object_unref(layout);
// cleanup notifs // cleanup notifs
std::erase_if(m_vNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; }); std::erase_if(m_notifications, [](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}; return CBox{(int)(pMonitor->m_position.x + pMonitor->m_size.x - maxWidth - 20), (int)pMonitor->m_position.y, (int)maxWidth + 20, (int)offsetY + 10};
} }
void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) { void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
const auto MONSIZE = pMonitor->vecTransformedSize; const auto MONSIZE = pMonitor->m_transformedSize;
if (m_pLastMonitor != pMonitor || m_vecLastSize != MONSIZE || !m_pCairo || !m_pCairoSurface) { if (m_lastMonitor != pMonitor || m_lastSize != MONSIZE || !m_cairo || !m_cairoSurface) {
if (m_pCairo && m_pCairoSurface) { if (m_cairo && m_cairoSurface) {
cairo_destroy(m_pCairo); cairo_destroy(m_cairo);
cairo_surface_destroy(m_pCairoSurface); cairo_surface_destroy(m_cairoSurface);
} }
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, MONSIZE.x, MONSIZE.y); m_cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, MONSIZE.x, MONSIZE.y);
m_pCairo = cairo_create(m_pCairoSurface); m_cairo = cairo_create(m_cairoSurface);
m_pLastMonitor = pMonitor; m_lastMonitor = pMonitor;
m_vecLastSize = MONSIZE; m_lastSize = MONSIZE;
} }
// Draw the notifications // Draw the notifications
if (m_vNotifications.size() == 0) if (m_notifications.size() == 0)
return; return;
// Render to the monitor // Render to the monitor
// clear the pixmap // clear the pixmap
cairo_save(m_pCairo); cairo_save(m_cairo);
cairo_set_operator(m_pCairo, CAIRO_OPERATOR_CLEAR); cairo_set_operator(m_cairo, CAIRO_OPERATOR_CLEAR);
cairo_paint(m_pCairo); cairo_paint(m_cairo);
cairo_restore(m_pCairo); cairo_restore(m_cairo);
cairo_surface_flush(m_pCairoSurface); cairo_surface_flush(m_cairoSurface);
CBox damage = drawNotifications(pMonitor); CBox damage = drawNotifications(pMonitor);
g_pHyprRenderer->damageBox(damage); g_pHyprRenderer->damageBox(damage);
g_pHyprRenderer->damageBox(m_bLastDamage); g_pHyprRenderer->damageBox(m_lastDamage);
g_pCompositor->scheduleFrameForMonitor(pMonitor); g_pCompositor->scheduleFrameForMonitor(pMonitor);
m_bLastDamage = damage; m_lastDamage = damage;
// copy the data to an OpenGL texture we have // copy the data to an OpenGL texture we have
const auto DATA = cairo_image_surface_get_data(m_pCairoSurface); const auto DATA = cairo_image_surface_get_data(m_cairoSurface);
m_pTexture->allocate(); m_texture->allocate();
glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID); glBindTexture(GL_TEXTURE_2D, m_texture->m_texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -247,13 +247,13 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CTexPassElement::SRenderData data; CTexPassElement::SRenderData data;
data.tex = m_pTexture; data.tex = m_texture;
data.box = {0, 0, MONSIZE.x, MONSIZE.y}; data.box = {0, 0, MONSIZE.x, MONSIZE.y};
data.a = 1.F; data.a = 1.F;
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data)); g_pHyprRenderer->m_renderPass.add(makeShared<CTexPassElement>(data));
} }
bool CHyprNotificationOverlay::hasAny() { bool CHyprNotificationOverlay::hasAny() {
return !m_vNotifications.empty(); return !m_notifications.empty();
} }

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/Timer.hpp" #include "../helpers/time/Timer.hpp"
#include "../render/Texture.hpp" #include "../render/Texture.hpp"
#include "../SharedDefs.hpp" #include "../SharedDefs.hpp"
@@ -47,17 +47,17 @@ class CHyprNotificationOverlay {
private: private:
CBox drawNotifications(PHLMONITOR pMonitor); CBox drawNotifications(PHLMONITOR pMonitor);
CBox m_bLastDamage; CBox m_lastDamage;
std::vector<UP<SNotification>> m_vNotifications; std::vector<UP<SNotification>> m_notifications;
cairo_surface_t* m_pCairoSurface = nullptr; cairo_surface_t* m_cairoSurface = nullptr;
cairo_t* m_pCairo = nullptr; cairo_t* m_cairo = nullptr;
PHLMONITORREF m_pLastMonitor; PHLMONITORREF m_lastMonitor;
Vector2D m_vecLastSize = Vector2D(-1, -1); Vector2D m_lastSize = Vector2D(-1, -1);
SP<CTexture> m_pTexture; SP<CTexture> m_texture;
}; };
inline UP<CHyprNotificationOverlay> g_pHyprNotificationOverlay; inline UP<CHyprNotificationOverlay> g_pHyprNotificationOverlay;

View File

@@ -7,21 +7,21 @@
#include <fcntl.h> #include <fcntl.h>
void Debug::init(const std::string& IS) { void Debug::init(const std::string& IS) {
logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); m_logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
logOfs.open(logFile, std::ios::out | std::ios::app); m_logOfs.open(m_logFile, std::ios::out | std::ios::app);
auto handle = logOfs.native_handle(); auto handle = m_logOfs.native_handle();
fcntl(handle, F_SETFD, FD_CLOEXEC); fcntl(handle, F_SETFD, FD_CLOEXEC);
} }
void Debug::close() { void Debug::close() {
logOfs.close(); m_logOfs.close();
} }
void Debug::log(eLogLevel level, std::string str) { void Debug::log(eLogLevel level, std::string str) {
if (level == TRACE && !trace) if (level == TRACE && !m_trace)
return; return;
if (shuttingDown) if (m_shuttingDown)
return; return;
std::string coloredStr = str; std::string coloredStr = str;
@@ -55,20 +55,20 @@ void Debug::log(eLogLevel level, std::string str) {
} }
//NOLINTEND //NOLINTEND
rollingLog += str + "\n"; m_rollingLog += str + "\n";
if (rollingLog.size() > ROLLING_LOG_SIZE) if (m_rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE); m_rollingLog = m_rollingLog.substr(m_rollingLog.size() - ROLLING_LOG_SIZE);
if (SRollingLogFollow::get().isRunning()) if (SRollingLogFollow::get().isRunning())
SRollingLogFollow::get().addLog(str); SRollingLogFollow::get().addLog(str);
if (!disableLogs || !**disableLogs) { if (!m_disableLogs || !**m_disableLogs) {
// log to a file // log to a file
logOfs << str << "\n"; m_logOfs << str << "\n";
logOfs.flush(); m_logOfs.flush();
} }
// log it to the stdout too. // log it to the stdout too.
if (!disableStdout) if (!m_disableStdout)
std::println("{}", ((coloredLogs && !**coloredLogs) ? str : coloredStr)); std::println("{}", ((m_coloredLogs && !**m_coloredLogs) ? str : coloredStr));
} }

View File

@@ -21,17 +21,17 @@ enum eLogLevel : int8_t {
// NOLINTNEXTLINE(readability-identifier-naming) // NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug { namespace Debug {
inline std::string logFile; inline std::string m_logFile;
inline std::ofstream logOfs; inline std::ofstream m_logOfs;
inline int64_t* const* disableLogs = nullptr; inline int64_t* const* m_disableLogs = nullptr;
inline int64_t* const* disableTime = nullptr; inline int64_t* const* m_disableTime = nullptr;
inline bool disableStdout = false; inline bool m_disableStdout = false;
inline bool trace = false; inline bool m_trace = false;
inline bool shuttingDown = false; inline bool m_shuttingDown = false;
inline int64_t* const* coloredLogs = nullptr; inline int64_t* const* m_coloredLogs = nullptr;
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log inline std::string m_rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
inline std::mutex logMutex; inline std::mutex m_logMutex;
void init(const std::string& IS); void init(const std::string& IS);
void close(); void close();
@@ -42,18 +42,18 @@ namespace Debug {
template <typename... Args> template <typename... Args>
//NOLINTNEXTLINE //NOLINTNEXTLINE
void log(eLogLevel level, std::format_string<Args...> fmt, Args&&... args) { void log(eLogLevel level, std::format_string<Args...> fmt, Args&&... args) {
std::lock_guard<std::mutex> guard(logMutex); std::lock_guard<std::mutex> guard(m_logMutex);
if (level == TRACE && !trace) if (level == TRACE && !m_trace)
return; return;
if (shuttingDown) if (m_shuttingDown)
return; return;
std::string logMsg = ""; std::string logMsg = "";
// print date and time to the ofs // print date and time to the ofs
if (disableTime && !**disableTime) { if (m_disableTime && !**m_disableTime) {
#ifndef _LIBCPP_VERSION #ifndef _LIBCPP_VERSION
static auto current_zone = std::chrono::current_zone(); static auto current_zone = std::chrono::current_zone();
const auto zt = std::chrono::zoned_time{current_zone, std::chrono::system_clock::now()}; const auto zt = std::chrono::zoned_time{current_zone, std::chrono::system_clock::now()};

View File

@@ -5,55 +5,55 @@
// NOLINTNEXTLINE(readability-identifier-naming) // NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug { namespace Debug {
struct SRollingLogFollow { struct SRollingLogFollow {
std::unordered_map<int, std::string> socketToRollingLogFollowQueue; std::unordered_map<int, std::string> m_socketToRollingLogFollowQueue;
std::shared_mutex m; std::shared_mutex m_mutex;
bool running = false; bool m_running = false;
static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192; static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192;
// Returns true if the queue is empty for the given socket // Returns true if the queue is empty for the given socket
bool isEmpty(int socket) { bool isEmpty(int socket) {
std::shared_lock<std::shared_mutex> r(m); std::shared_lock<std::shared_mutex> r(m_mutex);
return socketToRollingLogFollowQueue[socket].empty(); return m_socketToRollingLogFollowQueue[socket].empty();
} }
std::string debugInfo() { std::string debugInfo() {
std::shared_lock<std::shared_mutex> r(m); std::shared_lock<std::shared_mutex> r(m_mutex);
return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size()); return std::format("RollingLogFollow, got {} connections", m_socketToRollingLogFollowQueue.size());
} }
std::string getLog(int socket) { std::string getLog(int socket) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m_mutex);
const std::string ret = socketToRollingLogFollowQueue[socket]; const std::string ret = m_socketToRollingLogFollowQueue[socket];
socketToRollingLogFollowQueue[socket] = ""; m_socketToRollingLogFollowQueue[socket] = "";
return ret; return ret;
}; };
void addLog(const std::string& log) { void addLog(const std::string& log) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m_mutex);
running = true; m_running = true;
std::vector<int> to_erase; std::vector<int> to_erase;
for (const auto& p : socketToRollingLogFollowQueue) for (const auto& p : m_socketToRollingLogFollowQueue)
socketToRollingLogFollowQueue[p.first] += log + "\n"; m_socketToRollingLogFollowQueue[p.first] += log + "\n";
} }
bool isRunning() { bool isRunning() {
std::shared_lock<std::shared_mutex> r(m); std::shared_lock<std::shared_mutex> r(m_mutex);
return running; return m_running;
} }
void stopFor(int socket) { void stopFor(int socket) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m_mutex);
socketToRollingLogFollowQueue.erase(socket); m_socketToRollingLogFollowQueue.erase(socket);
if (socketToRollingLogFollowQueue.empty()) if (m_socketToRollingLogFollowQueue.empty())
running = false; m_running = false;
} }
void startFor(int socket) { void startFor(int socket) {
std::unique_lock<std::shared_mutex> w(m); std::unique_lock<std::shared_mutex> w(m_mutex);
socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket); m_socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket);
running = true; m_running = true;
} }
static SRollingLogFollow& get() { static SRollingLogFollow& get() {

View File

@@ -5,34 +5,36 @@
#include "../debug/Log.hpp" #include "../debug/Log.hpp"
static const auto RULES = std::unordered_set<std::string>{"noanim", "blur", "blurpopups", "dimaround"}; 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"}; static const auto RULES_PREFIX = std::unordered_set<std::string>{"ignorealpha", "ignorezero", "xray", "animation", "order", "abovelock"};
CLayerRule::CLayerRule(const std::string& rule_, const std::string& ns_) : targetNamespace(ns_), rule(rule_) { CLayerRule::CLayerRule(const std::string& rule_, const std::string& ns_) : m_targetNamespace(ns_), m_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); }); const bool VALID = RULES.contains(m_rule) || std::ranges::any_of(RULES_PREFIX, [&rule_](const auto& prefix) { return rule_.starts_with(prefix); });
if (!VALID) if (!VALID)
return; return;
if (rule == "noanim") if (m_rule == "noanim")
ruleType = RULE_NOANIM; m_ruleType = RULE_NOANIM;
else if (rule == "blur") else if (m_rule == "blur")
ruleType = RULE_BLUR; m_ruleType = RULE_BLUR;
else if (rule == "blurpopups") else if (m_rule == "blurpopups")
ruleType = RULE_BLURPOPUPS; m_ruleType = RULE_BLURPOPUPS;
else if (rule == "dimaround") else if (m_rule == "dimaround")
ruleType = RULE_DIMAROUND; m_ruleType = RULE_DIMAROUND;
else if (rule.starts_with("ignorealpha")) else if (m_rule.starts_with("ignorealpha"))
ruleType = RULE_IGNOREALPHA; m_ruleType = RULE_IGNOREALPHA;
else if (rule.starts_with("ignorezero")) else if (m_rule.starts_with("ignorezero"))
ruleType = RULE_IGNOREZERO; m_ruleType = RULE_IGNOREZERO;
else if (rule.starts_with("xray")) else if (m_rule.starts_with("xray"))
ruleType = RULE_XRAY; m_ruleType = RULE_XRAY;
else if (rule.starts_with("animation")) else if (m_rule.starts_with("animation"))
ruleType = RULE_ANIMATION; m_ruleType = RULE_ANIMATION;
else if (rule.starts_with("order")) else if (m_rule.starts_with("order"))
ruleType = RULE_ORDER; m_ruleType = RULE_ORDER;
else if (m_rule.starts_with("abovelock"))
m_ruleType = RULE_ABOVELOCK;
else { else {
Debug::log(ERR, "CLayerRule: didn't match a rule that was found valid?!"); Debug::log(ERR, "CLayerRule: didn't match a rule that was found valid?!");
ruleType = RULE_INVALID; m_ruleType = RULE_INVALID;
} }
} }

View File

@@ -14,6 +14,7 @@ class CLayerRule {
RULE_BLUR, RULE_BLUR,
RULE_BLURPOPUPS, RULE_BLURPOPUPS,
RULE_DIMAROUND, RULE_DIMAROUND,
RULE_ABOVELOCK,
RULE_IGNOREALPHA, RULE_IGNOREALPHA,
RULE_IGNOREZERO, RULE_IGNOREZERO,
RULE_XRAY, RULE_XRAY,
@@ -22,10 +23,10 @@ class CLayerRule {
RULE_ZUMBA, RULE_ZUMBA,
}; };
eRuleType ruleType = RULE_INVALID; eRuleType m_ruleType = RULE_INVALID;
const std::string targetNamespace; const std::string m_targetNamespace;
const std::string rule; const std::string m_rule;
CRuleRegexContainer targetNamespaceRegex; CRuleRegexContainer m_targetNamespaceRegex;
}; };

View File

@@ -15,424 +15,436 @@
PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) { PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource)); PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource));
auto pMonitor = resource->monitor.empty() ? g_pCompositor->m_pLastMonitor.lock() : g_pCompositor->getMonitorFromName(resource->monitor); auto pMonitor = resource->m_monitor.empty() ? g_pCompositor->m_lastMonitor.lock() : g_pCompositor->getMonitorFromName(resource->m_monitor);
pLS->surface->assign(resource->surface.lock(), pLS); pLS->m_surface->assign(resource->m_surface.lock(), pLS);
if (!pMonitor) { if (!pMonitor) {
Debug::log(ERR, "New LS has no monitor??"); Debug::log(ERR, "New LS has no monitor??");
return pLS; return pLS;
} }
if (pMonitor->pMirrorOf) if (pMonitor->m_mirrorOf)
pMonitor = g_pCompositor->m_vMonitors.front(); pMonitor = g_pCompositor->m_monitors.front();
pLS->self = pLS; pLS->m_self = pLS;
pLS->szNamespace = resource->layerNamespace; pLS->m_namespace = resource->m_layerNamespace;
pLS->layer = resource->current.layer; pLS->m_layer = resource->m_current.layer;
pLS->popupHead = CPopup::create(pLS); pLS->m_popupHead = CPopup::create(pLS);
pLS->monitor = pMonitor; pLS->m_monitor = pMonitor;
pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pMonitor->m_layerSurfaceLayers[resource->m_current.layer].emplace_back(pLS);
pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); pLS->m_forceBlur = g_pConfigManager->shouldBlurLS(pLS->m_namespace);
g_pAnimationManager->createAnimation(0.f, pLS->alpha, g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pLS->m_alpha, g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realPosition, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->m_realPosition, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realSize, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->m_realSize, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE);
pLS->registerCallbacks(); pLS->registerCallbacks();
pLS->alpha->setValueAndWarp(0.f); pLS->m_alpha->setValueAndWarp(0.f);
Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName); Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->m_layerNamespace, (int)pLS->m_layer, pMonitor->m_name);
return pLS; return pLS;
} }
void CLayerSurface::registerCallbacks() { void CLayerSurface::registerCallbacks() {
alpha->setUpdateCallback([this](auto) { m_alpha->setUpdateCallback([this](auto) {
if (dimAround) if (m_dimAround)
g_pHyprRenderer->damageMonitor(monitor.lock()); g_pHyprRenderer->damageMonitor(m_monitor.lock());
}); });
} }
CLayerSurface::CLayerSurface(SP<CLayerShellResource> resource_) : layerSurface(resource_) { CLayerSurface::CLayerSurface(SP<CLayerShellResource> resource_) : m_layerSurface(resource_) {
listeners.commit = layerSurface->events.commit.registerListener([this](std::any d) { onCommit(); }); m_listeners.commit = m_layerSurface->m_events.commit.registerListener([this](std::any d) { onCommit(); });
listeners.map = layerSurface->events.map.registerListener([this](std::any d) { onMap(); }); m_listeners.map = m_layerSurface->m_events.map.registerListener([this](std::any d) { onMap(); });
listeners.unmap = layerSurface->events.unmap.registerListener([this](std::any d) { onUnmap(); }); m_listeners.unmap = m_layerSurface->m_events.unmap.registerListener([this](std::any d) { onUnmap(); });
listeners.destroy = layerSurface->events.destroy.registerListener([this](std::any d) { onDestroy(); }); m_listeners.destroy = m_layerSurface->m_events.destroy.registerListener([this](std::any d) { onDestroy(); });
surface = CWLSurface::create(); m_surface = CWLSurface::create();
} }
CLayerSurface::~CLayerSurface() { CLayerSurface::~CLayerSurface() {
if (!g_pHyprOpenGL) if (!g_pHyprOpenGL)
return; return;
if (surface) if (m_surface)
surface->unassign(); m_surface->unassign();
g_pHyprRenderer->makeEGLCurrent(); g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); }); std::erase_if(g_pHyprOpenGL->m_layerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == m_self.lock(); });
for (auto const& mon : g_pCompositor->m_vRealMonitors) { for (auto const& mon : g_pCompositor->m_realMonitors) {
for (auto& lsl : mon->m_aLayerSurfaceLayers) { for (auto& lsl : mon->m_layerSurfaceLayers) {
std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; });
} }
} }
} }
void CLayerSurface::onDestroy() { void CLayerSurface::onDestroy() {
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get()); Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)m_layerSurface.get());
const auto PMONITOR = monitor.lock(); const auto PMONITOR = m_monitor.lock();
if (!PMONITOR) if (!PMONITOR)
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)"); Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
if (!fadingOut) { if (!m_fadingOut) {
if (mapped) { if (m_mapped) {
Debug::log(LOG, "Forcing an unmap of a LS that did a straight destroy!"); Debug::log(LOG, "Forcing an unmap of a LS that did a straight destroy!");
onUnmap(); onUnmap();
} else { } else {
Debug::log(LOG, "Removing LayerSurface that wasn't mapped."); Debug::log(LOG, "Removing LayerSurface that wasn't mapped.");
if (alpha) if (m_alpha)
alpha->setValueAndWarp(0.f); m_alpha->setValueAndWarp(0.f);
fadingOut = true; m_fadingOut = true;
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(m_self.lock());
} }
} }
popupHead.reset(); m_popupHead.reset();
noProcess = true; m_noProcess = true;
// rearrange to fix the reserved areas // rearrange to fix the reserved areas
if (PMONITOR) { if (PMONITOR) {
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id);
PMONITOR->scheduledRecalc = true; PMONITOR->m_scheduledRecalc = true;
// and damage // and damage
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y, m_geometry.width, m_geometry.height};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
} }
readyToDelete = true; m_readyToDelete = true;
layerSurface.reset(); m_layerSurface.reset();
if (surface) if (m_surface)
surface->unassign(); m_surface->unassign();
listeners.unmap.reset(); m_listeners.unmap.reset();
listeners.destroy.reset(); m_listeners.destroy.reset();
listeners.map.reset(); m_listeners.map.reset();
listeners.commit.reset(); m_listeners.commit.reset();
} }
void CLayerSurface::onMap() { void CLayerSurface::onMap() {
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface.get()); Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)m_layerSurface.get());
mapped = true; m_mapped = true;
interactivity = layerSurface->current.interactivity; m_interactivity = m_layerSurface->m_current.interactivity;
layerSurface->surface->map(); m_layerSurface->m_surface->map();
// this layer might be re-mapped. // this layer might be re-mapped.
fadingOut = false; m_fadingOut = false;
g_pCompositor->removeFromFadingOutSafe(self.lock()); g_pCompositor->removeFromFadingOutSafe(m_self.lock());
// fix if it changed its mon // fix if it changed its mon
const auto PMONITOR = monitor.lock(); const auto PMONITOR = m_monitor.lock();
if (!PMONITOR) if (!PMONITOR)
return; return;
applyRules(); applyRules();
PMONITOR->scheduledRecalc = true; PMONITOR->m_scheduledRecalc = true;
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id);
surface->resource()->enter(PMONITOR->self.lock()); m_surface->resource()->enter(PMONITOR->m_self.lock());
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool ISEXCLUSIVE = m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
if (ISEXCLUSIVE) if (ISEXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(self); g_pInputManager->m_exclusiveLSes.push_back(m_self);
const bool GRABSFOCUS = ISEXCLUSIVE || const bool GRABSFOCUS = ISEXCLUSIVE ||
(layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && (m_layerSurface->m_current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained // don't focus if constrained
(g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())); (g_pSeatManager->m_mouse.expired() || !g_pInputManager->isConstrained()));
if (GRABSFOCUS) { if (GRABSFOCUS) {
// TODO: use the new superb really very cool grab // TODO: use the new superb really very cool grab
g_pSeatManager->setGrab(nullptr); g_pSeatManager->setGrab(nullptr);
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
g_pCompositor->focusSurface(surface->resource()); g_pCompositor->focusSurface(m_surface->resource());
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y);
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); g_pSeatManager->setPointerFocus(m_surface->resource(), LOCAL);
g_pInputManager->m_bEmptyFocusCursorSet = false; g_pInputManager->m_emptyFocusCursorSet = false;
} }
position = Vector2D(geometry.x, geometry.y); m_position = Vector2D(m_geometry.x, m_geometry.y);
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y, m_geometry.width, m_geometry.height};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
const bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; const bool FULLSCREEN = PMONITOR->m_activeWorkspace && PMONITOR->m_activeWorkspace->m_hasFullscreenWindow && PMONITOR->m_activeWorkspace->m_fullscreenMode == FSMODE_FULLSCREEN;
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); startAnimation(!(m_layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
readyToDelete = false; m_readyToDelete = false;
fadingOut = false; m_fadingOut = false;
g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", szNamespace}); g_pEventManager->postEvent(SHyprIPCEvent{.event = "openlayer", .data = m_namespace});
EMIT_HOOK_EVENT("openLayer", self.lock()); EMIT_HOOK_EVENT("openLayer", m_self.lock());
g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale); g_pCompositor->setPreferredScaleForSurface(m_surface->resource(), PMONITOR->m_scale);
g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform); g_pCompositor->setPreferredTransformForSurface(m_surface->resource(), PMONITOR->m_transform);
} }
void CLayerSurface::onUnmap() { void CLayerSurface::onUnmap() {
Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface.get()); Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)m_layerSurface.get());
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace}); g_pEventManager->postEvent(SHyprIPCEvent{.event = "closelayer", .data = m_layerSurface->m_layerNamespace});
EMIT_HOOK_EVENT("closeLayer", self.lock()); EMIT_HOOK_EVENT("closeLayer", m_self.lock());
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); std::erase_if(g_pInputManager->m_exclusiveLSes, [this](const auto& other) { return !other || other == m_self; });
if (!monitor || g_pCompositor->m_bUnsafeState) { if (!m_monitor || g_pCompositor->m_unsafeState) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(m_self.lock());
mapped = false; m_mapped = false;
if (layerSurface && layerSurface->surface) if (m_layerSurface && m_layerSurface->m_surface)
layerSurface->surface->unmap(); m_layerSurface->m_surface->unmap();
startAnimation(false); startAnimation(false);
return; return;
} }
// end any pending animations so that snapshot has right dimensions
m_realPosition->warp();
m_realSize->warp();
// make a snapshot and start fade // make a snapshot and start fade
g_pHyprRenderer->makeLayerSnapshot(self.lock()); g_pHyprRenderer->makeLayerSnapshot(m_self.lock());
startAnimation(false); startAnimation(false);
mapped = false; m_mapped = false;
if (layerSurface && layerSurface->surface) if (m_layerSurface && m_layerSurface->m_surface)
layerSurface->surface->unmap(); m_layerSurface->m_surface->unmap();
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(m_self.lock());
const auto PMONITOR = monitor.lock(); const auto PMONITOR = m_monitor.lock();
const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == surface->resource() || g_pSeatManager->state.pointerFocus == surface->resource(); const bool WASLASTFOCUS = g_pSeatManager->m_state.keyboardFocus == m_surface->resource() || g_pSeatManager->m_state.pointerFocus == m_surface->resource();
if (!PMONITOR) if (!PMONITOR)
return; return;
// refocus if needed // refocus if needed
// vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable())) if (WASLASTFOCUS || (g_pCompositor->m_lastFocus && g_pCompositor->m_lastFocus->m_hlSurface && !g_pCompositor->m_lastFocus->m_hlSurface->keyboardFocusable())) {
g_pInputManager->refocusLastWindow(PMONITOR); if (!g_pInputManager->refocusLastWindow(PMONITOR))
else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource()) g_pInputManager->refocus();
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock()); } else if (g_pCompositor->m_lastFocus && g_pCompositor->m_lastFocus != m_surface->resource())
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_lastFocus.lock());
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y, m_geometry.width, m_geometry.height};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.size.x, geomFixed = {m_geometry.x + (int)PMONITOR->m_position.x, m_geometry.y + (int)PMONITOR->m_position.y, (int)m_layerSurface->m_surface->m_current.size.x,
(int)layerSurface->surface->current.size.y}; (int)m_layerSurface->m_surface->m_current.size.y};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id);
} }
void CLayerSurface::onCommit() { void CLayerSurface::onCommit() {
if (!layerSurface) if (!m_layerSurface)
return; return;
if (!mapped) { if (!m_mapped) {
// we're re-mapping if this is the case // we're re-mapping if this is the case
if (layerSurface->surface && !layerSurface->surface->current.texture) { if (m_layerSurface->m_surface && !m_layerSurface->m_surface->m_current.texture) {
fadingOut = false; m_fadingOut = false;
geometry = {}; m_geometry = {};
g_pHyprRenderer->arrangeLayersForMonitor(monitorID()); g_pHyprRenderer->arrangeLayersForMonitor(monitorID());
} }
return; return;
} }
const auto PMONITOR = monitor.lock(); const auto PMONITOR = m_monitor.lock();
if (!PMONITOR) if (!PMONITOR)
return; return;
if (layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) if (m_layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || m_layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
CBox geomFixed = {geometry.x, geometry.y, geometry.width, geometry.height}; CBox geomFixed = {m_geometry.x, m_geometry.y, m_geometry.width, m_geometry.height};
g_pHyprRenderer->damageBox(geomFixed); g_pHyprRenderer->damageBox(geomFixed);
if (layerSurface->current.committed != 0) { if (m_layerSurface->m_current.committed != 0) {
if (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_LAYER) { if (m_layerSurface->m_current.committed & CLayerShellResource::eCommittedState::STATE_LAYER) {
for (auto it = PMONITOR->m_aLayerSurfaceLayers[layer].begin(); it != PMONITOR->m_aLayerSurfaceLayers[layer].end(); it++) { for (auto it = PMONITOR->m_layerSurfaceLayers[m_layer].begin(); it != PMONITOR->m_layerSurfaceLayers[m_layer].end(); it++) {
if (*it == self) { if (*it == m_self) {
if (layerSurface->current.layer == layer) if (m_layerSurface->m_current.layer == m_layer)
break; break;
PMONITOR->m_aLayerSurfaceLayers[layerSurface->current.layer].emplace_back(*it); PMONITOR->m_layerSurfaceLayers[m_layerSurface->m_current.layer].emplace_back(*it);
PMONITOR->m_aLayerSurfaceLayers[layer].erase(it); PMONITOR->m_layerSurfaceLayers[m_layer].erase(it);
break; break;
} }
} }
layer = layerSurface->current.layer; m_layer = m_layerSurface->m_current.layer;
if (layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) if (m_layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || m_layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd
} }
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id);
PMONITOR->scheduledRecalc = true; PMONITOR->m_scheduledRecalc = true;
} else { } else {
position = Vector2D(geometry.x, geometry.y); m_position = Vector2D(m_geometry.x, m_geometry.y);
// update geom if it changed // update geom if it changed
if (layerSurface->surface->current.scale == 1 && PMONITOR->scale != 1.f && layerSurface->surface->current.viewport.hasDestination) { if (m_layerSurface->m_surface->m_current.scale == 1 && PMONITOR->m_scale != 1.f && m_layerSurface->m_surface->m_current.viewport.hasDestination) {
// fractional scaling. Dirty hack. // fractional scaling. Dirty hack.
geometry = {geometry.pos(), layerSurface->surface->current.viewport.destination}; m_geometry = {m_geometry.pos(), m_layerSurface->m_surface->m_current.viewport.destination};
} else { } else {
// this is because some apps like e.g. rofi-lbonn can't fucking use the protocol correctly. // this is because some apps like e.g. rofi-lbonn can't fucking use the protocol correctly.
geometry = {geometry.pos(), layerSurface->surface->current.size}; m_geometry = {m_geometry.pos(), m_layerSurface->m_surface->m_current.size};
} }
} }
if (realPosition->goal() != geometry.pos()) { if (m_realPosition->goal() != m_geometry.pos()) {
if (realPosition->isBeingAnimated()) if (m_realPosition->isBeingAnimated())
*realPosition = geometry.pos(); *m_realPosition = m_geometry.pos();
else else
realPosition->setValueAndWarp(geometry.pos()); m_realPosition->setValueAndWarp(m_geometry.pos());
} }
if (realSize->goal() != geometry.size()) { if (m_realSize->goal() != m_geometry.size()) {
if (realSize->isBeingAnimated()) if (m_realSize->isBeingAnimated())
*realSize = geometry.size(); *m_realSize = m_geometry.size();
else else
realSize->setValueAndWarp(geometry.size()); m_realSize->setValueAndWarp(m_geometry.size());
} }
if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) { if (m_mapped && (m_layerSurface->m_current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) {
bool WASLASTFOCUS = false; bool WASLASTFOCUS = false;
layerSurface->surface->breadthfirst( m_layerSurface->m_surface->breadthfirst(
[&WASLASTFOCUS](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->state.keyboardFocus == surf; }, [&WASLASTFOCUS](SP<CWLSurfaceResource> surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->m_state.keyboardFocus == surf; },
nullptr); nullptr);
if (!WASLASTFOCUS && popupHead) { if (!WASLASTFOCUS && m_popupHead) {
popupHead->breadthfirst( m_popupHead->breadthfirst(
[&WASLASTFOCUS](WP<CPopup> popup, void* data) { [&WASLASTFOCUS](WP<CPopup> popup, void* data) {
WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource()); WASLASTFOCUS = WASLASTFOCUS || (popup->m_wlSurface && g_pSeatManager->m_state.keyboardFocus == popup->m_wlSurface->resource());
}, },
nullptr); nullptr);
} }
const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool WASEXCLUSIVE = m_interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool ISEXCLUSIVE = m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
if (!WASEXCLUSIVE && ISEXCLUSIVE) if (!WASEXCLUSIVE && ISEXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(self); g_pInputManager->m_exclusiveLSes.push_back(m_self);
else if (WASEXCLUSIVE && !ISEXCLUSIVE) else if (WASEXCLUSIVE && !ISEXCLUSIVE)
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); std::erase_if(g_pInputManager->m_exclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == m_self.lock(); });
// if the surface was focused and interactive but now isn't, refocus // if the surface was focused and interactive but now isn't, refocus
if (WASLASTFOCUS && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) { if (WASLASTFOCUS && m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) {
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either, // moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
// so unfocus the surface here. // so unfocus the surface here.
g_pCompositor->focusSurface(nullptr); g_pCompositor->focusSurface(nullptr);
g_pInputManager->refocusLastWindow(monitor.lock()); g_pInputManager->refocusLastWindow(m_monitor.lock());
} else if (WASLASTFOCUS && WASEXCLUSIVE && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { } else if (WASLASTFOCUS && WASEXCLUSIVE && m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) {
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
} else if (!WASEXCLUSIVE && ISEXCLUSIVE) { } else if (!WASEXCLUSIVE && ISEXCLUSIVE) {
// if now exclusive and not previously // if now exclusive and not previously
g_pSeatManager->setGrab(nullptr); g_pSeatManager->setGrab(nullptr);
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
g_pCompositor->focusSurface(surface->resource()); g_pCompositor->focusSurface(m_surface->resource());
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y);
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); g_pSeatManager->setPointerFocus(m_surface->resource(), LOCAL);
g_pInputManager->m_bEmptyFocusCursorSet = false; g_pInputManager->m_emptyFocusCursorSet = false;
} }
} }
interactivity = layerSurface->current.interactivity; m_interactivity = m_layerSurface->m_current.interactivity;
g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y); g_pHyprRenderer->damageSurface(m_surface->resource(), m_position.x, m_position.y);
g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale); g_pCompositor->setPreferredScaleForSurface(m_surface->resource(), PMONITOR->m_scale);
g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform); g_pCompositor->setPreferredTransformForSurface(m_surface->resource(), PMONITOR->m_transform);
} }
void CLayerSurface::applyRules() { void CLayerSurface::applyRules() {
noAnimations = false; m_noAnimations = false;
forceBlur = false; m_forceBlur = false;
ignoreAlpha = false; m_ignoreAlpha = false;
ignoreAlphaValue = 0.f; m_ignoreAlphaValue = 0.f;
dimAround = false; m_dimAround = false;
xray = -1; m_xray = -1;
animationStyle.reset(); m_animationStyle.reset();
for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) { for (auto const& rule : g_pConfigManager->getMatchingRules(m_self.lock())) {
switch (rule->ruleType) { switch (rule->m_ruleType) {
case CLayerRule::RULE_NOANIM: { case CLayerRule::RULE_NOANIM: {
noAnimations = true; m_noAnimations = true;
break; break;
} }
case CLayerRule::RULE_BLUR: { case CLayerRule::RULE_BLUR: {
forceBlur = true; m_forceBlur = true;
break; break;
} }
case CLayerRule::RULE_BLURPOPUPS: { case CLayerRule::RULE_BLURPOPUPS: {
forceBlurPopups = true; m_forceBlurPopups = true;
break; break;
} }
case CLayerRule::RULE_IGNOREALPHA: case CLayerRule::RULE_IGNOREALPHA:
case CLayerRule::RULE_IGNOREZERO: { case CLayerRule::RULE_IGNOREZERO: {
const auto FIRST_SPACE_POS = rule->rule.find_first_of(' '); const auto FIRST_SPACE_POS = rule->m_rule.find_first_of(' ');
std::string alphaValue = ""; std::string alphaValue = "";
if (FIRST_SPACE_POS != std::string::npos) if (FIRST_SPACE_POS != std::string::npos)
alphaValue = rule->rule.substr(FIRST_SPACE_POS + 1); alphaValue = rule->m_rule.substr(FIRST_SPACE_POS + 1);
try { try {
ignoreAlpha = true; m_ignoreAlpha = true;
if (!alphaValue.empty()) if (!alphaValue.empty())
ignoreAlphaValue = std::stof(alphaValue); m_ignoreAlphaValue = std::stof(alphaValue);
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); } } catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
break; break;
} }
case CLayerRule::RULE_DIMAROUND: { case CLayerRule::RULE_DIMAROUND: {
dimAround = true; m_dimAround = true;
break; break;
} }
case CLayerRule::RULE_XRAY: { case CLayerRule::RULE_XRAY: {
CVarList vars{rule->rule, 0, ' '}; CVarList vars{rule->m_rule, 0, ' '};
try { m_xray = configStringToInt(vars[1]).value_or(false);
xray = configStringToInt(vars[1]).value_or(false);
} catch (...) {}
break; break;
} }
case CLayerRule::RULE_ANIMATION: { case CLayerRule::RULE_ANIMATION: {
CVarList vars{rule->rule, 2, 's'}; CVarList vars{rule->m_rule, 2, 's'};
animationStyle = vars[1]; m_animationStyle = vars[1];
break; break;
} }
case CLayerRule::RULE_ORDER: { case CLayerRule::RULE_ORDER: {
CVarList vars{rule->rule, 2, 's'}; CVarList vars{rule->m_rule, 2, 's'};
try { try {
order = std::stoi(vars[1]); m_order = std::stoi(vars[1]);
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); } } catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
break; break;
} }
case CLayerRule::RULE_ABOVELOCK: {
m_aboveLockscreen = true;
CVarList vars{rule->m_rule, 0, ' '};
m_aboveLockscreenInteractable = configStringToInt(vars[1]).value_or(false);
break;
}
default: break; default: break;
} }
} }
@@ -440,19 +452,19 @@ void CLayerSurface::applyRules() {
void CLayerSurface::startAnimation(bool in, bool instant) { void CLayerSurface::startAnimation(bool in, bool instant) {
if (in) { if (in) {
realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn"));
realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn"));
alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn")); m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"));
} else { } else {
realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut"));
realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut"));
alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut")); m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut"));
} }
const auto ANIMSTYLE = animationStyle.value_or(realPosition->getStyle()); const auto ANIMSTYLE = m_animationStyle.value_or(m_realPosition->getStyle());
if (ANIMSTYLE.starts_with("slide")) { if (ANIMSTYLE.starts_with("slide")) {
// get closest edge // get closest edge
const auto MIDDLE = geometry.middle(); const auto MIDDLE = m_geometry.middle();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE); const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE);
@@ -472,10 +484,10 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
} }
const std::array<Vector2D, 4> edgePoints = { const std::array<Vector2D, 4> edgePoints = {
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0.0}, PMONITOR->m_position + Vector2D{PMONITOR->m_size.x / 2, 0.0},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y}, PMONITOR->m_position + Vector2D{PMONITOR->m_size.x / 2, PMONITOR->m_size.y},
PMONITOR->vecPosition + Vector2D{0.0, PMONITOR->vecSize.y}, PMONITOR->m_position + Vector2D{0.0, PMONITOR->m_size.y},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2}, PMONITOR->m_position + Vector2D{PMONITOR->m_size.x, PMONITOR->m_size.y / 2},
}; };
float closest = std::numeric_limits<float>::max(); float closest = std::numeric_limits<float>::max();
@@ -490,38 +502,38 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
} }
} }
realSize->setValueAndWarp(geometry.size()); m_realSize->setValueAndWarp(m_geometry.size());
alpha->setValueAndWarp(in ? 0.f : 1.f); m_alpha->setValueAndWarp(in ? 0.f : 1.f);
*alpha = in ? 1.f : 0.f; *m_alpha = in ? 1.f : 0.f;
Vector2D prePos; Vector2D prePos;
switch (leader) { switch (leader) {
case 0: case 0:
// TOP // TOP
prePos = {geometry.x, PMONITOR->vecPosition.y - geometry.h}; prePos = {m_geometry.x, PMONITOR->m_position.y - m_geometry.h};
break; break;
case 1: case 1:
// BOTTOM // BOTTOM
prePos = {geometry.x, PMONITOR->vecPosition.y + PMONITOR->vecSize.y}; prePos = {m_geometry.x, PMONITOR->m_position.y + PMONITOR->m_size.y};
break; break;
case 2: case 2:
// LEFT // LEFT
prePos = {PMONITOR->vecPosition.x - geometry.w, geometry.y}; prePos = {PMONITOR->m_position.x - m_geometry.w, m_geometry.y};
break; break;
case 3: case 3:
// RIGHT // RIGHT
prePos = {PMONITOR->vecPosition.x + PMONITOR->vecSize.x, geometry.y}; prePos = {PMONITOR->m_position.x + PMONITOR->m_size.x, m_geometry.y};
break; break;
default: UNREACHABLE(); default: UNREACHABLE();
} }
if (in) { if (in) {
realPosition->setValueAndWarp(prePos); m_realPosition->setValueAndWarp(prePos);
*realPosition = geometry.pos(); *m_realPosition = m_geometry.pos();
} else { } else {
realPosition->setValueAndWarp(geometry.pos()); m_realPosition->setValueAndWarp(m_geometry.pos());
*realPosition = prePos; *m_realPosition = prePos;
} }
} else if (ANIMSTYLE.starts_with("popin")) { } else if (ANIMSTYLE.starts_with("popin")) {
@@ -537,62 +549,62 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
minPerc *= 0.01; minPerc *= 0.01;
const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5}); const auto GOALSIZE = (m_geometry.size() * minPerc).clamp({5, 5});
const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f; const auto GOALPOS = m_geometry.pos() + (m_geometry.size() - GOALSIZE) / 2.f;
alpha->setValueAndWarp(in ? 0.f : 1.f); m_alpha->setValueAndWarp(in ? 0.f : 1.f);
*alpha = in ? 1.f : 0.f; *m_alpha = in ? 1.f : 0.f;
if (in) { if (in) {
realSize->setValueAndWarp(GOALSIZE); m_realSize->setValueAndWarp(GOALSIZE);
realPosition->setValueAndWarp(GOALPOS); m_realPosition->setValueAndWarp(GOALPOS);
*realSize = geometry.size(); *m_realSize = m_geometry.size();
*realPosition = geometry.pos(); *m_realPosition = m_geometry.pos();
} else { } else {
realSize->setValueAndWarp(geometry.size()); m_realSize->setValueAndWarp(m_geometry.size());
realPosition->setValueAndWarp(geometry.pos()); m_realPosition->setValueAndWarp(m_geometry.pos());
*realSize = GOALSIZE; *m_realSize = GOALSIZE;
*realPosition = GOALPOS; *m_realPosition = GOALPOS;
} }
} else { } else {
// fade // fade
realPosition->setValueAndWarp(geometry.pos()); m_realPosition->setValueAndWarp(m_geometry.pos());
realSize->setValueAndWarp(geometry.size()); m_realSize->setValueAndWarp(m_geometry.size());
*alpha = in ? 1.f : 0.f; *m_alpha = in ? 1.f : 0.f;
} }
if (!in) if (!in)
fadingOut = true; m_fadingOut = true;
} }
bool CLayerSurface::isFadedOut() { bool CLayerSurface::isFadedOut() {
if (!fadingOut) if (!m_fadingOut)
return false; return false;
return !realPosition->isBeingAnimated() && !realSize->isBeingAnimated() && !alpha->isBeingAnimated(); return !m_realPosition->isBeingAnimated() && !m_realSize->isBeingAnimated() && !m_alpha->isBeingAnimated();
} }
int CLayerSurface::popupsCount() { int CLayerSurface::popupsCount() {
if (!layerSurface || !mapped || fadingOut) if (!m_layerSurface || !m_mapped || m_fadingOut)
return 0; return 0;
int no = -1; // we have one dummy int no = -1; // we have one dummy
popupHead->breadthfirst([](WP<CPopup> p, void* data) { *(int*)data += 1; }, &no); m_popupHead->breadthfirst([](WP<CPopup> p, void* data) { *(int*)data += 1; }, &no);
return no; return no;
} }
MONITORID CLayerSurface::monitorID() { MONITORID CLayerSurface::monitorID() {
return monitor ? monitor->ID : MONITOR_INVALID; return m_monitor ? m_monitor->m_id : MONITOR_INVALID;
} }
pid_t CLayerSurface::getPID() { pid_t CLayerSurface::getPID() {
pid_t PID = -1; pid_t PID = -1;
if (!layerSurface || !layerSurface->surface || !layerSurface->surface->getResource() || !layerSurface->surface->getResource()->resource() || if (!m_layerSurface || !m_layerSurface->m_surface || !m_layerSurface->m_surface->getResource() || !m_layerSurface->m_surface->getResource()->resource() ||
!layerSurface->surface->getResource()->resource()->client) !m_layerSurface->m_surface->getResource()->resource()->client)
return -1; return -1;
wl_client_get_credentials(layerSurface->surface->getResource()->resource()->client, &PID, nullptr, nullptr); wl_client_get_credentials(m_layerSurface->m_surface->getResource()->resource()->client, &PID, nullptr, nullptr);
return PID; return PID;
} }

View File

@@ -22,44 +22,45 @@ class CLayerSurface {
bool isFadedOut(); bool isFadedOut();
int popupsCount(); int popupsCount();
PHLANIMVAR<Vector2D> realPosition; PHLANIMVAR<Vector2D> m_realPosition;
PHLANIMVAR<Vector2D> realSize; PHLANIMVAR<Vector2D> m_realSize;
PHLANIMVAR<float> alpha; PHLANIMVAR<float> m_alpha;
WP<CLayerShellResource> layerSurface; WP<CLayerShellResource> m_layerSurface;
wl_list link;
// the header providing the enum type cannot be imported here // the header providing the enum type cannot be imported here
int interactivity = 0; int m_interactivity = 0;
SP<CWLSurface> surface; SP<CWLSurface> m_surface;
bool mapped = false; bool m_mapped = false;
uint32_t layer = 0; uint32_t m_layer = 0;
PHLMONITORREF monitor; PHLMONITORREF m_monitor;
bool fadingOut = false; bool m_fadingOut = false;
bool readyToDelete = false; bool m_readyToDelete = false;
bool noProcess = false; bool m_noProcess = false;
bool noAnimations = false; bool m_noAnimations = false;
bool forceBlur = false; bool m_forceBlur = false;
bool forceBlurPopups = false; bool m_forceBlurPopups = false;
int64_t xray = -1; int64_t m_xray = -1;
bool ignoreAlpha = false; bool m_ignoreAlpha = false;
float ignoreAlphaValue = 0.f; float m_ignoreAlphaValue = 0.f;
bool dimAround = false; bool m_dimAround = false;
int64_t order = 0; int64_t m_order = 0;
bool m_aboveLockscreen = false;
bool m_aboveLockscreenInteractable = false;
std::optional<std::string> animationStyle; std::optional<std::string> m_animationStyle;
PHLLSREF self; PHLLSREF m_self;
CBox geometry = {0, 0, 0, 0}; CBox m_geometry = {0, 0, 0, 0};
Vector2D position; Vector2D m_position;
std::string szNamespace = ""; std::string m_namespace = "";
UP<CPopup> popupHead; UP<CPopup> m_popupHead;
pid_t getPID(); pid_t getPID();
@@ -75,12 +76,12 @@ class CLayerSurface {
CHyprSignalListener map; CHyprSignalListener map;
CHyprSignalListener unmap; CHyprSignalListener unmap;
CHyprSignalListener commit; CHyprSignalListener commit;
} listeners; } m_listeners;
void registerCallbacks(); void registerCallbacks();
// For the list lookup // For the list lookup
bool operator==(const CLayerSurface& rhs) const { bool operator==(const CLayerSurface& rhs) const {
return layerSurface == rhs.layerSurface && monitor == rhs.monitor; return m_layerSurface == rhs.m_layerSurface && m_monitor == rhs.m_monitor;
} }
}; };

View File

@@ -5,7 +5,6 @@
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp" #include "../managers/SeatManager.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include "../desktop/LayerSurface.hpp" #include "../desktop/LayerSurface.hpp"
#include "../managers/input/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
@@ -13,32 +12,32 @@
#include <ranges> #include <ranges>
UP<CPopup> CPopup::create(PHLWINDOW pOwner) { UP<CPopup> CPopup::create(PHLWINDOW pOwner) {
auto popup = UP<CPopup>(new CPopup()); auto popup = UP<CPopup>(new CPopup());
popup->m_pWindowOwner = pOwner; popup->m_windowOwner = pOwner;
popup->m_pSelf = popup; popup->m_self = popup;
popup->initAllSignals(); popup->initAllSignals();
return popup; return popup;
} }
UP<CPopup> CPopup::create(PHLLS pOwner) { UP<CPopup> CPopup::create(PHLLS pOwner) {
auto popup = UP<CPopup>(new CPopup()); auto popup = UP<CPopup>(new CPopup());
popup->m_pLayerOwner = pOwner; popup->m_layerOwner = pOwner;
popup->m_pSelf = popup; popup->m_self = popup;
popup->initAllSignals(); popup->initAllSignals();
return popup; return popup;
} }
UP<CPopup> CPopup::create(SP<CXDGPopupResource> resource, WP<CPopup> pOwner) { UP<CPopup> CPopup::create(SP<CXDGPopupResource> resource, WP<CPopup> pOwner) {
auto popup = UP<CPopup>(new CPopup()); auto popup = UP<CPopup>(new CPopup());
popup->m_pResource = resource; popup->m_resource = resource;
popup->m_pWindowOwner = pOwner->m_pWindowOwner; popup->m_windowOwner = pOwner->m_windowOwner;
popup->m_pLayerOwner = pOwner->m_pLayerOwner; popup->m_layerOwner = pOwner->m_layerOwner;
popup->m_pParent = pOwner; popup->m_parent = pOwner;
popup->m_pSelf = popup; popup->m_self = popup;
popup->m_pWLSurface = CWLSurface::create(); popup->m_wlSurface = CWLSurface::create();
popup->m_pWLSurface->assign(resource->surface->surface.lock(), popup.get()); popup->m_wlSurface->assign(resource->m_surface->m_surface.lock(), popup.get());
popup->m_vLastSize = resource->surface->current.geometry.size(); popup->m_lastSize = resource->m_surface->m_current.geometry.size();
popup->reposition(); popup->reposition();
popup->initAllSignals(); popup->initAllSignals();
@@ -46,104 +45,114 @@ UP<CPopup> CPopup::create(SP<CXDGPopupResource> resource, WP<CPopup> pOwner) {
} }
CPopup::~CPopup() { CPopup::~CPopup() {
if (m_pWLSurface) if (m_wlSurface)
m_pWLSurface->unassign(); m_wlSurface->unassign();
} }
void CPopup::initAllSignals() { void CPopup::initAllSignals() {
if (!m_pResource) { if (!m_resource) {
if (!m_pWindowOwner.expired()) if (!m_windowOwner.expired())
listeners.newPopup = m_pWindowOwner->m_pXDGSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); }); m_listeners.newPopup =
else if (!m_pLayerOwner.expired()) m_windowOwner->m_xdgSurface->m_events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
listeners.newPopup = m_pLayerOwner->layerSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); }); else if (!m_layerOwner.expired())
m_listeners.newPopup =
m_layerOwner->m_layerSurface->m_events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
else else
ASSERT(false); ASSERT(false);
return; return;
} }
listeners.reposition = m_pResource->events.reposition.registerListener([this](std::any d) { this->onReposition(); }); m_listeners.reposition = m_resource->m_events.reposition.registerListener([this](std::any d) { this->onReposition(); });
listeners.map = m_pResource->surface->events.map.registerListener([this](std::any d) { this->onMap(); }); m_listeners.map = m_resource->m_surface->m_events.map.registerListener([this](std::any d) { this->onMap(); });
listeners.unmap = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); }); m_listeners.unmap = m_resource->m_surface->m_events.unmap.registerListener([this](std::any d) { this->onUnmap(); });
listeners.dismissed = m_pResource->events.dismissed.registerListener([this](std::any d) { this->onUnmap(); }); m_listeners.dismissed = m_resource->m_events.dismissed.registerListener([this](std::any d) { this->onUnmap(); });
listeners.destroy = m_pResource->surface->events.destroy.registerListener([this](std::any d) { this->onDestroy(); }); m_listeners.destroy = m_resource->m_surface->m_events.destroy.registerListener([this](std::any d) { this->onDestroy(); });
listeners.commit = m_pResource->surface->events.commit.registerListener([this](std::any d) { this->onCommit(); }); m_listeners.commit = m_resource->m_surface->m_events.commit.registerListener([this](std::any d) { this->onCommit(); });
listeners.newPopup = m_pResource->surface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); }); m_listeners.newPopup = m_resource->m_surface->m_events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast<SP<CXDGPopupResource>>(d)); });
} }
void CPopup::onNewPopup(SP<CXDGPopupResource> popup) { void CPopup::onNewPopup(SP<CXDGPopupResource> popup) {
const auto& POPUP = m_vChildren.emplace_back(CPopup::create(popup, m_pSelf)); const auto& POPUP = m_children.emplace_back(CPopup::create(popup, m_self));
POPUP->m_pSelf = POPUP; POPUP->m_self = POPUP;
Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP);
} }
void CPopup::onDestroy() { void CPopup::onDestroy() {
m_bInert = true; m_inert = true;
if (!m_pParent) if (!m_parent)
return; // head node return; // head node
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; }); std::erase_if(m_parent->m_children, [this](const auto& other) { return other.get() == this; });
} }
void CPopup::onMap() { void CPopup::onMap() {
if (m_bMapped) if (m_mapped)
return; return;
m_bMapped = true; m_mapped = true;
m_vLastSize = m_pResource->surface->surface->current.size; m_lastSize = m_resource->m_surface->m_surface->m_current.size;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS); const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
CBox box = m_pWLSurface->resource()->extends(); CBox box = m_wlSurface->resource()->extends();
box.translate(COORDS).expand(4); box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
m_vLastPos = coordsRelativeToParent(); m_lastPos = coordsRelativeToParent();
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
m_pSubsurfaceHead = CSubsurface::create(m_pSelf); m_subsurfaceHead = CSubsurface::create(m_self);
//unconstrain(); //unconstrain();
sendScale(); sendScale();
m_pResource->surface->surface->enter(PMONITOR->self.lock()); m_resource->m_surface->m_surface->enter(PMONITOR->m_self.lock());
if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) if (!m_layerOwner.expired() && m_layerOwner->m_layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_layerOwner->m_layer));
} }
void CPopup::onUnmap() { void CPopup::onUnmap() {
if (!m_bMapped) if (!m_mapped)
return; return;
if (!m_pResource || !m_pResource->surface) { if (!m_resource || !m_resource->m_surface) {
Debug::log(ERR, "CPopup: orphaned (no surface/resource) and unmaps??"); Debug::log(ERR, "CPopup: orphaned (no surface/resource) and unmaps??");
onDestroy(); onDestroy();
return; return;
} }
m_bMapped = false; m_mapped = false;
m_vLastSize = m_pResource->surface->surface->current.size; // if the popup committed a different size right now, we also need to damage the old size.
const Vector2D MAX_DAMAGE_SIZE = {std::max(m_lastSize.x, m_resource->m_surface->m_surface->m_current.size.x),
std::max(m_lastSize.y, m_resource->m_surface->m_surface->m_current.size.y)};
m_lastSize = m_resource->m_surface->m_surface->m_current.size;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
CBox box = m_pWLSurface->resource()->extends(); CBox box = m_wlSurface->resource()->extends();
box.translate(COORDS).expand(4); box.translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
m_pSubsurfaceHead.reset(); // damage the last popup's explicit max size as well
box = CBox{COORDS, MAX_DAMAGE_SIZE}.expand(4);
g_pHyprRenderer->damageBox(box);
if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) m_subsurfaceHead.reset();
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
if (!m_layerOwner.expired() && m_layerOwner->m_layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_layerOwner->m_layer));
// damage all children // damage all children
breadthfirst( breadthfirst(
[](WP<CPopup> p, void* data) { [](WP<CPopup> p, void* data) {
if (!p->m_pResource) if (!p->m_resource)
return; return;
auto box = CBox{p->coordsGlobal(), p->size()}; auto box = CBox{p->coordsGlobal(), p->size()};
@@ -159,59 +168,59 @@ void CPopup::onUnmap() {
} }
void CPopup::onCommit(bool ignoreSiblings) { void CPopup::onCommit(bool ignoreSiblings) {
if (!m_pResource || !m_pResource->surface) { if (!m_resource || !m_resource->m_surface) {
Debug::log(ERR, "CPopup: orphaned (no surface/resource) and commits??"); Debug::log(ERR, "CPopup: orphaned (no surface/resource) and commits??");
onDestroy(); onDestroy();
return; return;
} }
if (m_pResource->surface->initialCommit) { if (m_resource->m_surface->m_initialCommit) {
m_pResource->surface->scheduleConfigure(); m_resource->m_surface->scheduleConfigure();
return; return;
} }
if (!m_pWindowOwner.expired() && (!m_pWindowOwner->m_bIsMapped || !m_pWindowOwner->m_pWorkspace->m_bVisible)) { if (!m_windowOwner.expired() && (!m_windowOwner->m_isMapped || !m_windowOwner->m_workspace->m_visible)) {
m_vLastSize = m_pResource->surface->surface->current.size; m_lastSize = m_resource->m_surface->m_surface->m_current.size;
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage"); static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
if (*PLOGDAMAGE) if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_pWindowOwner.lock()); Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_windowOwner.lock());
return; return;
} }
if (!m_pResource->surface->mapped) if (!m_resource->m_surface->m_mapped)
return; return;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
const auto COORDSLOCAL = coordsRelativeToParent(); const auto COORDSLOCAL = coordsRelativeToParent();
if (m_vLastSize != m_pResource->surface->surface->current.size || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) { if (m_lastSize != m_resource->m_surface->m_surface->m_current.size || m_requestedReposition || m_lastPos != COORDSLOCAL) {
CBox box = {localToGlobal(m_vLastPos), m_vLastSize}; CBox box = {localToGlobal(m_lastPos), m_lastSize};
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
m_vLastSize = m_pResource->surface->surface->current.size; m_lastSize = m_resource->m_surface->m_surface->m_current.size;
box = {COORDS, m_vLastSize}; box = {COORDS, m_lastSize};
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
m_vLastPos = COORDSLOCAL; m_lastPos = COORDSLOCAL;
} }
if (!ignoreSiblings && m_pSubsurfaceHead) if (!ignoreSiblings && m_subsurfaceHead)
m_pSubsurfaceHead->recheckDamageForSubsurfaces(); m_subsurfaceHead->recheckDamageForSubsurfaces();
g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(m_wlSurface->resource(), COORDS.x, COORDS.y);
m_bRequestedReposition = false; m_requestedReposition = false;
if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) if (!m_layerOwner.expired() && m_layerOwner->m_layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_layerOwner->m_layer));
} }
void CPopup::onReposition() { void CPopup::onReposition() {
Debug::log(LOG, "Popup {:x} requests reposition", (uintptr_t)this); Debug::log(LOG, "Popup {:x} requests reposition", (uintptr_t)this);
m_bRequestedReposition = true; m_requestedReposition = true;
m_vLastPos = coordsRelativeToParent(); m_lastPos = coordsRelativeToParent();
reposition(); reposition();
} }
@@ -223,32 +232,32 @@ void CPopup::reposition() {
if (!PMONITOR) if (!PMONITOR)
return; return;
CBox box = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; CBox box = {PMONITOR->m_position.x, PMONITOR->m_position.y, PMONITOR->m_size.x, PMONITOR->m_size.y};
m_pResource->applyPositioning(box, COORDS); m_resource->applyPositioning(box, COORDS);
} }
SP<CWLSurface> CPopup::getT1Owner() { SP<CWLSurface> CPopup::getT1Owner() {
if (m_pWindowOwner) if (m_windowOwner)
return m_pWindowOwner->m_pWLSurface; return m_windowOwner->m_wlSurface;
else else
return m_pLayerOwner->surface; return m_layerOwner->m_surface;
} }
Vector2D CPopup::coordsRelativeToParent() { Vector2D CPopup::coordsRelativeToParent() {
Vector2D offset; Vector2D offset;
if (!m_pResource) if (!m_resource)
return {}; return {};
WP<CPopup> current = m_pSelf; WP<CPopup> current = m_self;
offset -= current->m_pResource->surface->current.geometry.pos(); offset -= current->m_resource->m_surface->m_current.geometry.pos();
while (current->m_pParent && current->m_pResource) { while (current->m_parent && current->m_resource) {
offset += current->m_pWLSurface->resource()->current.offset; offset += current->m_wlSurface->resource()->m_current.offset;
offset += current->m_pResource->geometry.pos(); offset += current->m_resource->m_geometry.pos();
current = current->m_pParent; current = current->m_parent;
} }
return offset; return offset;
@@ -263,30 +272,30 @@ Vector2D CPopup::localToGlobal(const Vector2D& rel) {
} }
Vector2D CPopup::t1ParentCoords() { Vector2D CPopup::t1ParentCoords() {
if (!m_pWindowOwner.expired()) if (!m_windowOwner.expired())
return m_pWindowOwner->m_vRealPosition->value(); return m_windowOwner->m_realPosition->value();
if (!m_pLayerOwner.expired()) if (!m_layerOwner.expired())
return m_pLayerOwner->realPosition->value(); return m_layerOwner->m_realPosition->value();
ASSERT(false); ASSERT(false);
return {}; return {};
} }
void CPopup::recheckTree() { void CPopup::recheckTree() {
WP<CPopup> curr = m_pSelf; WP<CPopup> curr = m_self;
while (curr->m_pParent) { while (curr->m_parent) {
curr = curr->m_pParent; curr = curr->m_parent;
} }
curr->recheckChildrenRecursive(); curr->recheckChildrenRecursive();
} }
void CPopup::recheckChildrenRecursive() { void CPopup::recheckChildrenRecursive() {
if (m_bInert || !m_pWLSurface) if (m_inert || !m_wlSurface)
return; return;
std::vector<WP<CPopup>> cpy; std::vector<WP<CPopup>> cpy;
std::ranges::for_each(m_vChildren, [&cpy](const auto& el) { cpy.emplace_back(el); }); std::ranges::for_each(m_children, [&cpy](const auto& el) { cpy.emplace_back(el); });
for (auto const& c : cpy) { for (auto const& c : cpy) {
c->onCommit(true); c->onCommit(true);
c->recheckChildrenRecursive(); c->recheckChildrenRecursive();
@@ -294,25 +303,25 @@ void CPopup::recheckChildrenRecursive() {
} }
Vector2D CPopup::size() { Vector2D CPopup::size() {
return m_vLastSize; return m_lastSize;
} }
void CPopup::sendScale() { void CPopup::sendScale() {
if (!m_pWindowOwner.expired()) if (!m_windowOwner.expired())
g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pWindowOwner->m_pWLSurface->m_fLastScale); g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), m_windowOwner->m_wlSurface->m_lastScaleFloat);
else if (!m_pLayerOwner.expired()) else if (!m_layerOwner.expired())
g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pLayerOwner->surface->m_fLastScale); g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), m_layerOwner->m_surface->m_lastScaleFloat);
else else
UNREACHABLE(); UNREACHABLE();
} }
bool CPopup::visible() { bool CPopup::visible() {
if (!m_pWindowOwner.expired()) if (!m_windowOwner.expired())
return g_pHyprRenderer->shouldRenderWindow(m_pWindowOwner.lock()); return g_pHyprRenderer->shouldRenderWindow(m_windowOwner.lock());
if (!m_pLayerOwner.expired()) if (!m_layerOwner.expired())
return true; return true;
if (m_pParent) if (m_parent)
return m_pParent->visible(); return m_parent->visible();
return false; return false;
} }
@@ -326,8 +335,8 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
nodes2.reserve(nodes.size() * 2); nodes2.reserve(nodes.size() * 2);
for (auto const& n : nodes) { for (auto const& n : nodes) {
for (auto const& c : n->m_vChildren) { for (auto const& c : n->m_children) {
nodes2.push_back(c->m_pSelf); nodes2.push_back(c->m_self);
} }
} }
@@ -337,7 +346,7 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
void CPopup::breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data) { void CPopup::breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data) {
std::vector<WP<CPopup>> popups; std::vector<WP<CPopup>> popups;
popups.push_back(m_pSelf); popups.push_back(m_self);
bfHelper(popups, fn, data); bfHelper(popups, fn, data);
} }
@@ -346,14 +355,14 @@ WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
breadthfirst([&popups](WP<CPopup> popup, void* data) { popups.push_back(popup); }, &popups); breadthfirst([&popups](WP<CPopup> popup, void* data) { popups.push_back(popup); }, &popups);
for (auto const& p : popups | std::views::reverse) { for (auto const& p : popups | std::views::reverse) {
if (!p->m_pResource || !p->m_bMapped) if (!p->m_resource || !p->m_mapped)
continue; continue;
if (!allowsInput) { if (!allowsInput) {
const bool HASSURFACE = p->m_pResource && p->m_pResource->surface; const bool HASSURFACE = p->m_resource && p->m_resource->m_surface;
Vector2D offset = HASSURFACE ? p->m_pResource->surface->current.geometry.pos() : Vector2D{}; Vector2D offset = HASSURFACE ? p->m_resource->m_surface->m_current.geometry.pos() : Vector2D{};
Vector2D size = HASSURFACE ? p->m_pResource->surface->current.geometry.size() : p->size(); Vector2D size = HASSURFACE ? p->m_resource->m_surface->m_current.geometry.size() : p->size();
if (size == Vector2D{}) if (size == Vector2D{})
size = p->size(); size = p->size();
@@ -362,7 +371,7 @@ WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
if (BOX.containsPoint(globalCoords)) if (BOX.containsPoint(globalCoords))
return p; return p;
} else { } else {
const auto REGION = CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal()); const auto REGION = CRegion{p->m_wlSurface->resource()->m_current.input}.intersect(CBox{{}, p->m_wlSurface->resource()->m_current.size}).translate(p->coordsGlobal());
if (REGION.containsPoint(globalCoords)) if (REGION.containsPoint(globalCoords))
return p; return p;
} }
@@ -372,5 +381,5 @@ WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
} }
bool CPopup::inert() const { bool CPopup::inert() const {
return m_bInert; return m_inert;
} }

View File

@@ -41,32 +41,32 @@ class CPopup {
WP<CPopup> at(const Vector2D& globalCoords, bool allowsInput = false); WP<CPopup> at(const Vector2D& globalCoords, bool allowsInput = false);
// //
SP<CWLSurface> m_pWLSurface; SP<CWLSurface> m_wlSurface;
WP<CPopup> m_pSelf; WP<CPopup> m_self;
bool m_bMapped = false; bool m_mapped = false;
private: private:
CPopup() = default; CPopup() = default;
// T1 owners, each popup has to have one of these // T1 owners, each popup has to have one of these
PHLWINDOWREF m_pWindowOwner; PHLWINDOWREF m_windowOwner;
PHLLSREF m_pLayerOwner; PHLLSREF m_layerOwner;
// T2 owners // T2 owners
WP<CPopup> m_pParent; WP<CPopup> m_parent;
WP<CXDGPopupResource> m_pResource; WP<CXDGPopupResource> m_resource;
Vector2D m_vLastSize = {}; Vector2D m_lastSize = {};
Vector2D m_vLastPos = {}; Vector2D m_lastPos = {};
bool m_bRequestedReposition = false; bool m_requestedReposition = false;
bool m_bInert = false; bool m_inert = false;
// //
std::vector<UP<CPopup>> m_vChildren; std::vector<UP<CPopup>> m_children;
UP<CSubsurface> m_pSubsurfaceHead; UP<CSubsurface> m_subsurfaceHead;
struct { struct {
CHyprSignalListener newPopup; CHyprSignalListener newPopup;
@@ -76,7 +76,7 @@ class CPopup {
CHyprSignalListener commit; CHyprSignalListener commit;
CHyprSignalListener dismissed; CHyprSignalListener dismissed;
CHyprSignalListener reposition; CHyprSignalListener reposition;
} listeners; } m_listeners;
void initAllSignals(); void initAllSignals();
void reposition(); void reposition();

View File

@@ -6,17 +6,17 @@
CRuleRegexContainer::CRuleRegexContainer(const std::string& regex_) { CRuleRegexContainer::CRuleRegexContainer(const std::string& regex_) {
const bool NEGATIVE = regex_.starts_with("negative:"); const bool NEGATIVE = regex_.starts_with("negative:");
negative = NEGATIVE; m_negative = NEGATIVE;
regex = makeUnique<RE2>(NEGATIVE ? regex_.substr(9) : regex_); m_regex = makeUnique<RE2>(NEGATIVE ? regex_.substr(9) : regex_);
// TODO: maybe pop an error? // TODO: maybe pop an error?
if (!regex->ok()) if (!m_regex->ok())
Debug::log(ERR, "RuleRegexContainer: regex {} failed to parse!", regex_); Debug::log(ERR, "RuleRegexContainer: regex {} failed to parse!", regex_);
} }
bool CRuleRegexContainer::passes(const std::string& str) const { bool CRuleRegexContainer::passes(const std::string& str) const {
if (!regex) if (!m_regex)
return false; return false;
return RE2::FullMatch(str, *regex) != negative; return RE2::FullMatch(str, *m_regex) != m_negative;
} }

View File

@@ -16,6 +16,6 @@ class CRuleRegexContainer {
bool passes(const std::string& str) const; bool passes(const std::string& str) const;
private: private:
Hyprutils::Memory::CUniquePointer<re2::RE2> regex; Hyprutils::Memory::CUniquePointer<re2::RE2> m_regex;
bool negative = false; bool m_negative = false;
}; };

View File

@@ -8,62 +8,62 @@
#include "../managers/input/InputManager.hpp" #include "../managers/input/InputManager.hpp"
UP<CSubsurface> CSubsurface::create(PHLWINDOW pOwner) { UP<CSubsurface> CSubsurface::create(PHLWINDOW pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); auto subsurface = UP<CSubsurface>(new CSubsurface());
subsurface->m_pWindowParent = pOwner; subsurface->m_windowParent = pOwner;
subsurface->m_pSelf = subsurface; subsurface->m_self = subsurface;
subsurface->initSignals(); subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); subsurface->initExistingSubsurfaces(pOwner->m_wlSurface->resource());
return subsurface; return subsurface;
} }
UP<CSubsurface> CSubsurface::create(WP<CPopup> pOwner) { UP<CSubsurface> CSubsurface::create(WP<CPopup> pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); auto subsurface = UP<CSubsurface>(new CSubsurface());
subsurface->m_pPopupParent = pOwner; subsurface->m_popupParent = pOwner;
subsurface->m_pSelf = subsurface; subsurface->m_self = subsurface;
subsurface->initSignals(); subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); subsurface->initExistingSubsurfaces(pOwner->m_wlSurface->resource());
return subsurface; return subsurface;
} }
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) { UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); auto subsurface = UP<CSubsurface>(new CSubsurface());
subsurface->m_pWindowParent = pOwner; subsurface->m_windowParent = pOwner;
subsurface->m_pSubsurface = pSubsurface; subsurface->m_subsurface = pSubsurface;
subsurface->m_pSelf = subsurface; subsurface->m_self = subsurface;
subsurface->m_pWLSurface = CWLSurface::create(); subsurface->m_wlSurface = CWLSurface::create();
subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); subsurface->m_wlSurface->assign(pSubsurface->m_surface.lock(), subsurface.get());
subsurface->initSignals(); subsurface->initSignals();
subsurface->initExistingSubsurfaces(pSubsurface->surface.lock()); subsurface->initExistingSubsurfaces(pSubsurface->m_surface.lock());
return subsurface; return subsurface;
} }
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner) { UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface()); auto subsurface = UP<CSubsurface>(new CSubsurface());
subsurface->m_pPopupParent = pOwner; subsurface->m_popupParent = pOwner;
subsurface->m_pSubsurface = pSubsurface; subsurface->m_subsurface = pSubsurface;
subsurface->m_pSelf = subsurface; subsurface->m_self = subsurface;
subsurface->m_pWLSurface = CWLSurface::create(); subsurface->m_wlSurface = CWLSurface::create();
subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); subsurface->m_wlSurface->assign(pSubsurface->m_surface.lock(), subsurface.get());
subsurface->initSignals(); subsurface->initSignals();
subsurface->initExistingSubsurfaces(pSubsurface->surface.lock()); subsurface->initExistingSubsurfaces(pSubsurface->m_surface.lock());
return subsurface; return subsurface;
} }
void CSubsurface::initSignals() { void CSubsurface::initSignals() {
if (m_pSubsurface) { if (m_subsurface) {
listeners.commitSubsurface = m_pSubsurface->surface->events.commit.registerListener([this](std::any d) { onCommit(); }); m_listeners.commitSubsurface = m_subsurface->m_surface->m_events.commit.registerListener([this](std::any d) { onCommit(); });
listeners.destroySubsurface = m_pSubsurface->events.destroy.registerListener([this](std::any d) { onDestroy(); }); m_listeners.destroySubsurface = m_subsurface->m_events.destroy.registerListener([this](std::any d) { onDestroy(); });
listeners.mapSubsurface = m_pSubsurface->surface->events.map.registerListener([this](std::any d) { onMap(); }); m_listeners.mapSubsurface = m_subsurface->m_surface->m_events.map.registerListener([this](std::any d) { onMap(); });
listeners.unmapSubsurface = m_pSubsurface->surface->events.unmap.registerListener([this](std::any d) { onUnmap(); }); m_listeners.unmapSubsurface = m_subsurface->m_surface->m_events.unmap.registerListener([this](std::any d) { onUnmap(); });
listeners.newSubsurface = m_listeners.newSubsurface =
m_pSubsurface->surface->events.newSubsurface.registerListener([this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); }); m_subsurface->m_surface->m_events.newSubsurface.registerListener([this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); });
} else { } else {
if (m_pWindowParent) if (m_windowParent)
listeners.newSubsurface = m_pWindowParent->m_pWLSurface->resource()->events.newSubsurface.registerListener( m_listeners.newSubsurface = m_windowParent->m_wlSurface->resource()->m_events.newSubsurface.registerListener(
[this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); }); [this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); });
else if (m_pPopupParent) else if (m_popupParent)
listeners.newSubsurface = m_pPopupParent->m_pWLSurface->resource()->events.newSubsurface.registerListener( m_listeners.newSubsurface = m_popupParent->m_wlSurface->resource()->m_events.newSubsurface.registerListener(
[this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); }); [this](std::any d) { onNewSubsurface(std::any_cast<SP<CWLSubsurfaceResource>>(d)); });
else else
ASSERT(false); ASSERT(false);
@@ -71,115 +71,102 @@ void CSubsurface::initSignals() {
} }
void CSubsurface::checkSiblingDamage() { void CSubsurface::checkSiblingDamage() {
if (!m_pParent) if (!m_parent)
return; // ?????????? return; // ??????????
const double SCALE = m_pWindowParent.lock() && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0; const double SCALE = m_windowParent.lock() && m_windowParent->m_isX11 ? 1.0 / m_windowParent->m_X11SurfaceScaledBy : 1.0;
for (auto const& n : m_pParent->m_vChildren) { for (auto const& n : m_parent->m_children) {
if (n.get() == this) if (n.get() == this)
continue; continue;
const auto COORDS = n->coordsGlobal(); const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y, SCALE); g_pHyprRenderer->damageSurface(n->m_wlSurface->resource(), COORDS.x, COORDS.y, SCALE);
} }
} }
void CSubsurface::recheckDamageForSubsurfaces() { void CSubsurface::recheckDamageForSubsurfaces() {
for (auto const& n : m_vChildren) { for (auto const& n : m_children) {
const auto COORDS = n->coordsGlobal(); const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(n->m_wlSurface->resource(), COORDS.x, COORDS.y);
} }
} }
void CSubsurface::onCommit() { void CSubsurface::onCommit() {
// no damaging if it's not visible // no damaging if it's not visible
if (!m_pWindowParent.expired() && (!m_pWindowParent->m_bIsMapped || !m_pWindowParent->m_pWorkspace->m_bVisible)) { if (!m_windowParent.expired() && (!m_windowParent->m_isMapped || !m_windowParent->m_workspace->m_visible)) {
m_vLastSize = m_pWLSurface->resource()->current.size; m_lastSize = m_wlSurface->resource()->m_current.size;
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage"); static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
if (*PLOGDAMAGE) if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_pWindowParent.lock()); Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_windowParent.lock());
return; return;
} }
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(m_wlSurface->resource(), COORDS.x, COORDS.y);
if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface) if (m_popupParent && !m_popupParent->inert() && m_popupParent->m_wlSurface)
m_pPopupParent->recheckTree(); m_popupParent->recheckTree();
if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this if (!m_windowParent.expired()) // I hate you firefox why are you doing this
m_pWindowParent->m_pPopupHead->recheckTree(); m_windowParent->m_popupHead->recheckTree();
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox) // I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
checkSiblingDamage(); checkSiblingDamage();
if (m_vLastSize != m_pWLSurface->resource()->current.size) { if (m_lastSize != m_wlSurface->resource()->m_current.size || m_lastPosition != m_subsurface->m_position) {
// TODO: fix this damageLastArea();
// CBox box{COORDS, m_vLastSize}; m_lastSize = m_wlSurface->resource()->m_current.size;
// g_pHyprRenderer->damageBox(box); m_lastPosition = m_subsurface->m_position;
// m_vLastSize = m_pWLSurface->resource()->current.size;
// box = {COORDS, m_vLastSize};
// g_pHyprRenderer->damageBox(box);
CBox box;
if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface)
box = m_pPopupParent->m_pWLSurface->getSurfaceBoxGlobal().value_or(CBox{});
else if (m_pWindowParent)
box = m_pWindowParent->getWindowMainSurfaceBox();
g_pHyprRenderer->damageBox(box);
} }
} }
void CSubsurface::onDestroy() { void CSubsurface::onDestroy() {
// destroy children // destroy children
m_vChildren.clear(); m_children.clear();
m_bInert = true; m_inert = true;
if (!m_pSubsurface) if (!m_subsurface)
return; // dummy node, nothing to do, it's the parent dying return; // dummy node, nothing to do, it's the parent dying
// kill ourselves // kill ourselves
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; }); std::erase_if(m_parent->m_children, [this](const auto& other) { return other.get() == this; });
} }
void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) { void CSubsurface::onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface) {
WP<CSubsurface> PSUBSURFACE; WP<CSubsurface> PSUBSURFACE;
if (!m_pWindowParent.expired()) if (!m_windowParent.expired())
PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pWindowParent.lock())); PSUBSURFACE = m_children.emplace_back(CSubsurface::create(pSubsurface, m_windowParent.lock()));
else if (m_pPopupParent) else if (m_popupParent)
PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pPopupParent)); PSUBSURFACE = m_children.emplace_back(CSubsurface::create(pSubsurface, m_popupParent));
PSUBSURFACE->m_pSelf = PSUBSURFACE; PSUBSURFACE->m_self = PSUBSURFACE;
ASSERT(PSUBSURFACE); ASSERT(PSUBSURFACE);
PSUBSURFACE->m_pParent = m_pSelf; PSUBSURFACE->m_parent = m_self;
} }
void CSubsurface::onMap() { void CSubsurface::onMap() {
m_vLastSize = m_pWLSurface->resource()->current.size; m_lastSize = m_wlSurface->resource()->m_current.size;
m_lastPosition = m_subsurface->m_position;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize}; CBox box{COORDS, m_lastSize};
box.expand(4); box.expand(4);
g_pHyprRenderer->damageBox(box); g_pHyprRenderer->damageBox(box);
if (!m_pWindowParent.expired()) if (!m_windowParent.expired())
m_pWindowParent->updateSurfaceScaleTransformDetails(); m_windowParent->updateSurfaceScaleTransformDetails();
} }
void CSubsurface::onUnmap() { void CSubsurface::onUnmap() {
const auto COORDS = coordsGlobal(); damageLastArea();
CBox box{COORDS, m_vLastSize};
box.expand(4);
g_pHyprRenderer->damageBox(box);
if (m_pWLSurface->resource() == g_pCompositor->m_pLastFocus) if (m_wlSurface->resource() == g_pCompositor->m_lastFocus)
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
@@ -187,42 +174,49 @@ void CSubsurface::onUnmap() {
// TODO: should this remove children? Currently it won't, only on .destroy // TODO: should this remove children? Currently it won't, only on .destroy
} }
void CSubsurface::damageLastArea() {
const auto COORDS = coordsGlobal() + m_lastPosition - m_subsurface->m_position;
CBox box{COORDS, m_lastSize};
box.expand(4);
g_pHyprRenderer->damageBox(box);
}
Vector2D CSubsurface::coordsRelativeToParent() { Vector2D CSubsurface::coordsRelativeToParent() {
if (!m_pSubsurface) if (!m_subsurface)
return {}; return {};
return m_pSubsurface->posRelativeToParent(); return m_subsurface->posRelativeToParent();
} }
Vector2D CSubsurface::coordsGlobal() { Vector2D CSubsurface::coordsGlobal() {
Vector2D coords = coordsRelativeToParent(); Vector2D coords = coordsRelativeToParent();
if (!m_pWindowParent.expired()) if (!m_windowParent.expired())
coords += m_pWindowParent->m_vRealPosition->value(); coords += m_windowParent->m_realPosition->value();
else if (m_pPopupParent) else if (m_popupParent)
coords += m_pPopupParent->coordsGlobal(); coords += m_popupParent->coordsGlobal();
return coords; return coords;
} }
void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) { void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) {
for (auto const& s : pSurface->subsurfaces) { for (auto const& s : pSurface->m_subsurfaces) {
if (!s || s->surface->hlSurface /* already assigned */) if (!s || s->m_surface->m_hlSurface /* already assigned */)
continue; continue;
onNewSubsurface(s.lock()); onNewSubsurface(s.lock());
} }
} }
Vector2D CSubsurface::size() { Vector2D CSubsurface::size() {
return m_pWLSurface->resource()->current.size; return m_wlSurface->resource()->m_current.size;
} }
bool CSubsurface::visible() { bool CSubsurface::visible() {
if (!m_pWindowParent.expired()) if (!m_windowParent.expired())
return g_pHyprRenderer->shouldRenderWindow(m_pWindowParent.lock()); return g_pHyprRenderer->shouldRenderWindow(m_windowParent.lock());
if (m_pPopupParent) if (m_popupParent)
return m_pPopupParent->visible(); return m_popupParent->visible();
if (m_pParent) if (m_parent)
return m_pParent->visible(); return m_parent->visible();
return false; return false;
} }

View File

@@ -34,7 +34,7 @@ class CSubsurface {
void recheckDamageForSubsurfaces(); void recheckDamageForSubsurfaces();
WP<CSubsurface> m_pSelf; WP<CSubsurface> m_self;
private: private:
CSubsurface() = default; CSubsurface() = default;
@@ -45,23 +45,25 @@ class CSubsurface {
CHyprSignalListener mapSubsurface; CHyprSignalListener mapSubsurface;
CHyprSignalListener unmapSubsurface; CHyprSignalListener unmapSubsurface;
CHyprSignalListener newSubsurface; CHyprSignalListener newSubsurface;
} listeners; } m_listeners;
WP<CWLSubsurfaceResource> m_pSubsurface; WP<CWLSubsurfaceResource> m_subsurface;
SP<CWLSurface> m_pWLSurface; SP<CWLSurface> m_wlSurface;
Vector2D m_vLastSize = {}; Vector2D m_lastSize = {};
Vector2D m_lastPosition = {};
// if nullptr, means it's a dummy node // if nullptr, means it's a dummy node
WP<CSubsurface> m_pParent; WP<CSubsurface> m_parent;
PHLWINDOWREF m_pWindowParent; PHLWINDOWREF m_windowParent;
WP<CPopup> m_pPopupParent; WP<CPopup> m_popupParent;
std::vector<UP<CSubsurface>> m_vChildren; std::vector<UP<CSubsurface>> m_children;
bool m_bInert = false; bool m_inert = false;
void initSignals(); void initSignals();
void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface); void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface);
void checkSiblingDamage(); void checkSiblingDamage();
void damageLastArea();
}; };

View File

@@ -6,37 +6,37 @@
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_pResource = pSurface; m_resource = pSurface;
init(); init();
m_bInert = false; m_inert = false;
} }
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner) {
m_pWindowOwner = pOwner; m_windowOwner = pOwner;
m_pResource = pSurface; m_resource = pSurface;
init(); init();
m_bInert = false; m_inert = false;
} }
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner) {
m_pLayerOwner = pOwner; m_layerOwner = pOwner;
m_pResource = pSurface; m_resource = pSurface;
init(); init();
m_bInert = false; m_inert = false;
} }
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner) {
m_pSubsurfaceOwner = pOwner; m_subsurfaceOwner = pOwner;
m_pResource = pSurface; m_resource = pSurface;
init(); init();
m_bInert = false; m_inert = false;
} }
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner) {
m_pPopupOwner = pOwner; m_popupOwner = pOwner;
m_pResource = pSurface; m_resource = pSurface;
init(); init();
m_bInert = false; m_inert = false;
} }
void CWLSurface::unassign() { void CWLSurface::unassign() {
@@ -48,66 +48,67 @@ CWLSurface::~CWLSurface() {
} }
bool CWLSurface::exists() const { bool CWLSurface::exists() const {
return m_pResource; return m_resource;
} }
SP<CWLSurfaceResource> CWLSurface::resource() const { SP<CWLSurfaceResource> CWLSurface::resource() const {
return m_pResource.lock(); return m_resource.lock();
} }
bool CWLSurface::small() const { bool CWLSurface::small() const {
if (!validMapped(m_pWindowOwner) || !exists()) if (!validMapped(m_windowOwner) || !exists())
return false; return false;
if (!m_pResource->current.texture) if (!m_resource->m_current.texture)
return false; return false;
const auto O = m_pWindowOwner.lock(); const auto O = m_windowOwner.lock();
return O->m_vReportedSize.x > m_pResource->current.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1; return O->m_reportedSize.x > m_resource->m_current.size.x + 1 || O->m_reportedSize.y > m_resource->m_current.size.y + 1;
} }
Vector2D CWLSurface::correctSmallVec() const { Vector2D CWLSurface::correctSmallVec() const {
if (!validMapped(m_pWindowOwner) || !exists() || !small() || m_bFillIgnoreSmall) if (!validMapped(m_windowOwner) || !exists() || !small() || m_fillIgnoreSmall)
return {}; return {};
const auto SIZE = getViewporterCorrectedSize(); const auto SIZE = getViewporterCorrectedSize();
const auto O = m_pWindowOwner.lock(); const auto O = m_windowOwner.lock();
return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize->value() / O->m_vReportedSize); return Vector2D{(O->m_reportedSize.x - SIZE.x) / 2, (O->m_reportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_realSize->value() / O->m_reportedSize);
} }
Vector2D CWLSurface::correctSmallVecBuf() const { Vector2D CWLSurface::correctSmallVecBuf() const {
if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.texture) if (!exists() || !small() || m_fillIgnoreSmall || !m_resource->m_current.texture)
return {}; return {};
const auto SIZE = getViewporterCorrectedSize(); const auto SIZE = getViewporterCorrectedSize();
const auto BS = m_pResource->current.bufferSize; const auto BS = m_resource->m_current.bufferSize;
return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}); return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY});
} }
Vector2D CWLSurface::getViewporterCorrectedSize() const { Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists() || !m_pResource->current.texture) if (!exists() || !m_resource->m_current.texture)
return {}; return {};
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.bufferSize; return m_resource->m_current.viewport.hasDestination ? m_resource->m_current.viewport.destination : m_resource->m_current.bufferSize;
} }
CRegion CWLSurface::computeDamage() const { CRegion CWLSurface::computeDamage() const {
if (!m_pResource->current.texture) if (!m_resource->m_current.texture)
return {}; return {};
CRegion damage = m_pResource->accumulateCurrentBufferDamage(); CRegion damage = m_resource->m_current.accumulateBufferDamage();
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y); damage.transform(wlTransformToHyprutils(m_resource->m_current.transform), m_resource->m_current.bufferSize.x, m_resource->m_current.bufferSize.y);
const auto BUFSIZE = m_pResource->current.bufferSize; const auto BUFSIZE = m_resource->m_current.bufferSize;
const auto CORRECTVEC = correctSmallVecBuf(); const auto CORRECTVEC = correctSmallVecBuf();
if (m_pResource->current.viewport.hasSource) if (m_resource->m_current.viewport.hasSource)
damage.intersect(m_pResource->current.viewport.source); damage.intersect(m_resource->m_current.viewport.source);
const auto SCALEDSRCSIZE = m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.bufferSize; const auto SCALEDSRCSIZE =
m_resource->m_current.viewport.hasSource ? m_resource->m_current.viewport.source.size() * m_resource->m_current.scale : m_resource->m_current.bufferSize;
damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y}); damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
damage.translate(CORRECTVEC); damage.translate(CORRECTVEC);
@@ -115,120 +116,120 @@ CRegion CWLSurface::computeDamage() const {
// go from buffer coords in the damage to hl logical // go from buffer coords in the damage to hl logical
const auto BOX = getSurfaceBoxGlobal(); const auto BOX = getSurfaceBoxGlobal();
const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.bufferSize : const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_resource->m_current.bufferSize :
Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */}; Vector2D{1.0 / m_resource->m_current.scale, 1.0 / m_resource->m_current.scale /* Wrong... but we can't really do better */};
damage.scale(SCALE); damage.scale(SCALE);
if (m_pWindowOwner) if (m_windowOwner)
damage.scale(m_pWindowOwner->m_fX11SurfaceScaledBy); // fix xwayland:force_zero_scaling stuff that will be fucked by the above a bit damage.scale(m_windowOwner->m_X11SurfaceScaledBy); // fix xwayland:force_zero_scaling stuff that will be fucked by the above a bit
return damage; return damage;
} }
void CWLSurface::destroy() { void CWLSurface::destroy() {
if (!m_pResource) if (!m_resource)
return; return;
events.destroy.emit(); m_events.destroy.emit();
m_pConstraint.reset(); m_constraint.reset();
listeners.destroy.reset(); m_listeners.destroy.reset();
m_pResource->hlSurface.reset(); m_resource->m_hlSurface.reset();
m_pWindowOwner.reset(); m_windowOwner.reset();
m_pLayerOwner.reset(); m_layerOwner.reset();
m_pPopupOwner = nullptr; m_popupOwner = nullptr;
m_pSubsurfaceOwner = nullptr; m_subsurfaceOwner = nullptr;
m_bInert = true; m_inert = true;
if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf && g_pHyprRenderer->m_sLastCursorData.surf->get() == this) if (g_pHyprRenderer && g_pHyprRenderer->m_lastCursorData.surf && g_pHyprRenderer->m_lastCursorData.surf->get() == this)
g_pHyprRenderer->m_sLastCursorData.surf.reset(); g_pHyprRenderer->m_lastCursorData.surf.reset();
m_pResource.reset(); m_resource.reset();
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this); Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
} }
void CWLSurface::init() { void CWLSurface::init() {
if (!m_pResource) if (!m_resource)
return; return;
RASSERT(!m_pResource->hlSurface, "Attempted to duplicate CWLSurface ownership!"); RASSERT(!m_resource->m_hlSurface, "Attempted to duplicate CWLSurface ownership!");
m_pResource->hlSurface = self.lock(); m_resource->m_hlSurface = m_self.lock();
listeners.destroy = m_pResource->events.destroy.registerListener([this](std::any d) { destroy(); }); m_listeners.destroy = m_resource->m_events.destroy.registerListener([this](std::any d) { destroy(); });
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this); Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
} }
PHLWINDOW CWLSurface::getWindow() const { PHLWINDOW CWLSurface::getWindow() const {
return m_pWindowOwner.lock(); return m_windowOwner.lock();
} }
PHLLS CWLSurface::getLayer() const { PHLLS CWLSurface::getLayer() const {
return m_pLayerOwner.lock(); return m_layerOwner.lock();
} }
CPopup* CWLSurface::getPopup() const { CPopup* CWLSurface::getPopup() const {
return m_pPopupOwner; return m_popupOwner;
} }
CSubsurface* CWLSurface::getSubsurface() const { CSubsurface* CWLSurface::getSubsurface() const {
return m_pSubsurfaceOwner; return m_subsurfaceOwner;
} }
bool CWLSurface::desktopComponent() const { bool CWLSurface::desktopComponent() const {
return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner; return !m_layerOwner.expired() || !m_windowOwner.expired() || m_subsurfaceOwner || m_popupOwner;
} }
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const { std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const {
if (!desktopComponent()) if (!desktopComponent())
return {}; return {};
if (!m_pWindowOwner.expired()) if (!m_windowOwner.expired())
return m_pWindowOwner->getWindowMainSurfaceBox(); return m_windowOwner->getWindowMainSurfaceBox();
if (!m_pLayerOwner.expired()) if (!m_layerOwner.expired())
return m_pLayerOwner->geometry; return m_layerOwner->m_geometry;
if (m_pPopupOwner) if (m_popupOwner)
return CBox{m_pPopupOwner->coordsGlobal(), m_pPopupOwner->size()}; return CBox{m_popupOwner->coordsGlobal(), m_popupOwner->size()};
if (m_pSubsurfaceOwner) if (m_subsurfaceOwner)
return CBox{m_pSubsurfaceOwner->coordsGlobal(), m_pSubsurfaceOwner->size()}; return CBox{m_subsurfaceOwner->coordsGlobal(), m_subsurfaceOwner->size()};
return {}; return {};
} }
void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) { void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) {
m_pConstraint = constraint; m_constraint = constraint;
} }
SP<CPointerConstraint> CWLSurface::constraint() const { SP<CPointerConstraint> CWLSurface::constraint() const {
return m_pConstraint.lock(); return m_constraint.lock();
} }
bool CWLSurface::visible() { bool CWLSurface::visible() {
if (!m_pWindowOwner.expired()) if (!m_windowOwner.expired())
return g_pHyprRenderer->shouldRenderWindow(m_pWindowOwner.lock()); return g_pHyprRenderer->shouldRenderWindow(m_windowOwner.lock());
if (!m_pLayerOwner.expired()) if (!m_layerOwner.expired())
return true; return true;
if (m_pPopupOwner) if (m_popupOwner)
return m_pPopupOwner->visible(); return m_popupOwner->visible();
if (m_pSubsurfaceOwner) if (m_subsurfaceOwner)
return m_pSubsurfaceOwner->visible(); return m_subsurfaceOwner->visible();
return true; // non-desktop, we don't know much. return true; // non-desktop, we don't know much.
} }
SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) { SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
if (!pSurface) if (!pSurface)
return nullptr; return nullptr;
return pSurface->hlSurface.lock(); return pSurface->m_hlSurface.lock();
} }
bool CWLSurface::keyboardFocusable() const { bool CWLSurface::keyboardFocusable() const {
if (m_pWindowOwner || m_pPopupOwner || m_pSubsurfaceOwner) if (m_windowOwner || m_popupOwner || m_subsurfaceOwner)
return true; return true;
if (m_pLayerOwner && m_pLayerOwner->layerSurface) if (m_layerOwner && m_layerOwner->m_layerSurface)
return m_pLayerOwner->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; return m_layerOwner->m_layerSurface->m_current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
return false; return false;
} }

View File

@@ -12,8 +12,8 @@ class CWLSurfaceResource;
class CWLSurface { class CWLSurface {
public: public:
static SP<CWLSurface> create() { static SP<CWLSurface> create() {
auto p = SP<CWLSurface>(new CWLSurface); auto p = SP<CWLSurface>(new CWLSurface);
p->self = p; p->m_self = p;
return p; return p;
} }
~CWLSurface(); ~CWLSurface();
@@ -53,17 +53,17 @@ class CWLSurface {
SP<CPointerConstraint> constraint() const; SP<CPointerConstraint> constraint() const;
// allow stretching. Useful for plugins. // allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false; bool m_fillIgnoreSmall = false;
// track surface data and avoid dupes // track surface data and avoid dupes
float m_fLastScale = 0; float m_lastScaleFloat = 0;
int m_iLastScale = 0; int m_lastScaleInt = 0;
wl_output_transform m_eLastTransform = (wl_output_transform)-1; wl_output_transform m_lastTransform = (wl_output_transform)-1;
// //
CWLSurface& operator=(SP<CWLSurfaceResource> pSurface) { CWLSurface& operator=(SP<CWLSurfaceResource> pSurface) {
destroy(); destroy();
m_pResource = pSurface; m_resource = pSurface;
init(); init();
return *this; return *this;
@@ -84,32 +84,32 @@ class CWLSurface {
static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface); static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface);
// used by the alpha-modifier protocol // used by the alpha-modifier protocol
float m_fAlphaModifier = 1.F; float m_alphaModifier = 1.F;
// used by the hyprland-surface protocol // used by the hyprland-surface protocol
float m_fOverallOpacity = 1.F; float m_overallOpacity = 1.F;
CRegion m_visibleRegion; CRegion m_visibleRegion;
struct { struct {
CSignal destroy; CSignal destroy;
} events; } m_events;
WP<CWLSurface> self; WP<CWLSurface> m_self;
private: private:
CWLSurface() = default; CWLSurface() = default;
bool m_bInert = true; bool m_inert = true;
WP<CWLSurfaceResource> m_pResource; WP<CWLSurfaceResource> m_resource;
PHLWINDOWREF m_pWindowOwner; PHLWINDOWREF m_windowOwner;
PHLLSREF m_pLayerOwner; PHLLSREF m_layerOwner;
CPopup* m_pPopupOwner = nullptr; CPopup* m_popupOwner = nullptr;
CSubsurface* m_pSubsurfaceOwner = nullptr; CSubsurface* m_subsurfaceOwner = nullptr;
// //
WP<CPointerConstraint> m_pConstraint; WP<CPointerConstraint> m_constraint;
void destroy(); void destroy();
void init(); void init();
@@ -117,7 +117,7 @@ class CWLSurface {
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
} listeners; } m_listeners;
friend class CPointerConstraint; friend class CPointerConstraint;
friend class CXxColorManagerV4; friend class CXxColorManagerV4;

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,6 @@
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/TagKeeper.hpp" #include "../helpers/TagKeeper.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../managers/XWaylandManager.hpp" #include "../managers/XWaylandManager.hpp"
@@ -19,6 +17,7 @@
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "Workspace.hpp" #include "Workspace.hpp"
#include "WindowRule.hpp" #include "WindowRule.hpp"
#include "WindowOverridableVar.hpp"
#include "../protocols/types/ContentType.hpp" #include "../protocols/types/ContentType.hpp"
class CXDGSurfaceResource; class CXDGSurfaceResource;
@@ -44,13 +43,14 @@ enum eGroupRules : uint8_t {
}; };
enum eGetWindowProperties : uint8_t { enum eGetWindowProperties : uint8_t {
WINDOW_ONLY = 0, WINDOW_ONLY = 0,
RESERVED_EXTENTS = 1 << 0, RESERVED_EXTENTS = 1 << 0,
INPUT_EXTENTS = 1 << 1, INPUT_EXTENTS = 1 << 1,
FULL_EXTENTS = 1 << 2, FULL_EXTENTS = 1 << 2,
FLOATING_ONLY = 1 << 3, FLOATING_ONLY = 1 << 3,
ALLOW_FLOATING = 1 << 4, ALLOW_FLOATING = 1 << 4,
USE_PROP_TILED = 1 << 5, USE_PROP_TILED = 1 << 5,
SKIP_FULLSCREEN_PRIORITY = 1 << 6,
}; };
enum eSuppressEvents : uint8_t { enum eSuppressEvents : uint8_t {
@@ -65,103 +65,21 @@ enum eSuppressEvents : uint8_t {
class IWindowTransformer; class IWindowTransformer;
struct SAlphaValue { struct SAlphaValue {
float m_fAlpha; float alpha;
bool m_bOverride; bool overridden;
float applyAlpha(float alpha) const { float applyAlpha(float a) const {
if (m_bOverride) if (overridden)
return m_fAlpha; return alpha;
else else
return m_fAlpha * alpha; return alpha * a;
}; };
}; };
enum eOverridePriority : uint8_t {
PRIORITY_LAYOUT = 0,
PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP,
};
template <typename T>
class CWindowOverridableVar {
public:
CWindowOverridableVar(T const& value, eOverridePriority priority) {
values[priority] = value;
}
CWindowOverridableVar(T const& value) : defaultValue{value} {}
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default;
CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> const& other) {
// Self-assignment check
if (this == &other)
return *this;
for (auto const& value : other.values) {
values[value.first] = value.second;
}
return *this;
}
void unset(eOverridePriority priority) {
values.erase(priority);
}
bool hasValue() {
return !values.empty();
}
T value() {
if (!values.empty())
return std::prev(values.end())->second;
else
throw std::bad_optional_access();
}
T valueOr(T const& other) {
if (hasValue())
return value();
else
return other;
}
T valueOrDefault() {
return valueOr(defaultValue);
}
eOverridePriority getPriority() {
if (!values.empty())
return std::prev(values.end())->first;
else
throw std::bad_optional_access();
}
void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
if (optValue.has_value())
values[priority] = optValue.value();
else
unset(priority);
}
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private:
std::map<eOverridePriority, T> values;
T defaultValue; // used for toggling, so required for bool
};
struct SWindowData { struct SWindowData {
CWindowOverridableVar<SAlphaValue> alpha = SAlphaValue{1.f, false}; CWindowOverridableVar<SAlphaValue> alpha = SAlphaValue{.alpha = 1.f, .overridden = false};
CWindowOverridableVar<SAlphaValue> alphaInactive = SAlphaValue{1.f, false}; CWindowOverridableVar<SAlphaValue> alphaInactive = SAlphaValue{.alpha = 1.f, .overridden = false};
CWindowOverridableVar<SAlphaValue> alphaFullscreen = SAlphaValue{1.f, false}; CWindowOverridableVar<SAlphaValue> alphaFullscreen = SAlphaValue{.alpha = 1.f, .overridden = false};
CWindowOverridableVar<bool> allowsInput = false; CWindowOverridableVar<bool> allowsInput = false;
CWindowOverridableVar<bool> dimAround = false; CWindowOverridableVar<bool> dimAround = false;
@@ -184,13 +102,14 @@ struct SWindowData {
CWindowOverridableVar<bool> tearing = false; CWindowOverridableVar<bool> tearing = false;
CWindowOverridableVar<bool> xray = false; CWindowOverridableVar<bool> xray = false;
CWindowOverridableVar<bool> renderUnfocused = false; CWindowOverridableVar<bool> renderUnfocused = false;
CWindowOverridableVar<bool> noFollowMouse = false;
CWindowOverridableVar<int> rounding; CWindowOverridableVar<Hyprlang::INT> borderSize = {std::string("general:border_size"), Hyprlang::INT(0), std::nullopt};
CWindowOverridableVar<float> roundingPower; CWindowOverridableVar<Hyprlang::INT> rounding = {std::string("decoration:rounding"), Hyprlang::INT(0), std::nullopt};
CWindowOverridableVar<int> borderSize;
CWindowOverridableVar<float> scrollMouse; CWindowOverridableVar<Hyprlang::FLOAT> roundingPower = {std::string("decoration:rounding_power")};
CWindowOverridableVar<float> scrollTouchpad; CWindowOverridableVar<Hyprlang::FLOAT> scrollMouse = {std::string("input:scroll_factor")};
CWindowOverridableVar<Hyprlang::FLOAT> scrollTouchpad = {std::string("input:touchpad:scroll_factor")};
CWindowOverridableVar<std::string> animationStyle; CWindowOverridableVar<std::string> animationStyle;
CWindowOverridableVar<Vector2D> maxSize; CWindowOverridableVar<Vector2D> maxSize;
@@ -224,154 +143,151 @@ class CWindow {
public: public:
~CWindow(); ~CWindow();
SP<CWLSurface> m_pWLSurface; SP<CWLSurface> m_wlSurface;
struct { struct {
CSignal destroy; CSignal destroy;
} events; } m_events;
WP<CXDGSurfaceResource> m_pXDGSurface; WP<CXDGSurfaceResource> m_xdgSurface;
WP<CXWaylandSurface> m_pXWaylandSurface; WP<CXWaylandSurface> m_xwaylandSurface;
// this is the position and size of the "bounding box" // this is the position and size of the "bounding box"
Vector2D m_vPosition = Vector2D(0, 0); Vector2D m_position = Vector2D(0, 0);
Vector2D m_vSize = Vector2D(0, 0); Vector2D m_size = Vector2D(0, 0);
// this is the real position and size used to draw the thing // this is the real position and size used to draw the thing
PHLANIMVAR<Vector2D> m_vRealPosition; PHLANIMVAR<Vector2D> m_realPosition;
PHLANIMVAR<Vector2D> m_vRealSize; PHLANIMVAR<Vector2D> m_realSize;
// for not spamming the protocols // for not spamming the protocols
Vector2D m_vReportedPosition; Vector2D m_reportedPosition;
Vector2D m_vReportedSize; Vector2D m_reportedSize;
Vector2D m_vPendingReportedSize; Vector2D m_pendingReportedSize;
std::optional<std::pair<uint32_t, Vector2D>> m_pPendingSizeAck; std::optional<std::pair<uint32_t, Vector2D>> m_pendingSizeAck;
std::vector<std::pair<uint32_t, Vector2D>> m_vPendingSizeAcks; std::vector<std::pair<uint32_t, Vector2D>> m_pendingSizeAcks;
// for restoring floating statuses // for restoring floating statuses
Vector2D m_vLastFloatingSize; Vector2D m_lastFloatingSize;
Vector2D m_vLastFloatingPosition; Vector2D m_lastFloatingPosition;
// for floating window offset in workspace animations // for floating window offset in workspace animations
Vector2D m_vFloatingOffset = Vector2D(0, 0); Vector2D m_floatingOffset = Vector2D(0, 0);
// this is used for pseudotiling // this is used for pseudotiling
bool m_bIsPseudotiled = false; bool m_isPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(1280, 720); Vector2D m_pseudoSize = Vector2D(1280, 720);
// for recovering relative cursor position // for recovering relative cursor position
Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1); Vector2D m_relativeCursorCoordsOnLastWarp = Vector2D(-1, -1);
bool m_bFirstMap = false; // for layouts bool m_firstMap = false; // for layouts
bool m_bIsFloating = false; bool m_isFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_draggingTiled = false; // for dragging around tiled windows
bool m_bWasMaximized = false; SFullscreenState m_fullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
SFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE}; std::string m_title = "";
std::string m_szTitle = ""; std::string m_class = "";
std::string m_szClass = ""; std::string m_initialTitle = "";
std::string m_szInitialTitle = ""; std::string m_initialClass = "";
std::string m_szInitialClass = ""; PHLWORKSPACE m_workspace;
PHLWORKSPACE m_pWorkspace; PHLMONITORREF m_monitor;
PHLMONITORREF m_pMonitor;
bool m_bIsMapped = false; bool m_isMapped = false;
bool m_bRequestsFloat = false; bool m_requestsFloat = false;
// This is for fullscreen apps // This is for fullscreen apps
bool m_bCreatedOverFullscreen = false; bool m_createdOverFullscreen = false;
// XWayland stuff // XWayland stuff
bool m_bIsX11 = false; bool m_isX11 = false;
PHLWINDOWREF m_pX11Parent; bool m_X11DoesntWantBorders = false;
bool m_bX11DoesntWantBorders = false; bool m_X11ShouldntFocus = false;
bool m_bX11ShouldntFocus = false; float m_X11SurfaceScaledBy = 1.f;
float m_fX11SurfaceScaledBy = 1.f;
// //
// For nofocus // For nofocus
bool m_bNoInitialFocus = false; bool m_noInitialFocus = false;
// Fullscreen and Maximize // Fullscreen and Maximize
bool m_bWantsInitialFullscreen = false; bool m_wantsInitialFullscreen = false;
MONITORID m_iWantsInitialFullscreenMonitor = MONITOR_INVALID; MONITORID m_wantsInitialFullscreenMonitor = MONITOR_INVALID;
// bitfield eSuppressEvents // bitfield suppressEvents
uint64_t m_eSuppressedEvents = SUPPRESS_NONE; uint64_t m_suppressedEvents = SUPPRESS_NONE;
// desktop components // desktop components
UP<CSubsurface> m_pSubsurfaceHead; UP<CSubsurface> m_subsurfaceHead;
UP<CPopup> m_pPopupHead; UP<CPopup> m_popupHead;
// Animated border // Animated border
CGradientValueData m_cRealBorderColor = {0}; CGradientValueData m_realBorderColor = {0};
CGradientValueData m_cRealBorderColorPrevious = {0}; CGradientValueData m_realBorderColorPrevious = {0};
PHLANIMVAR<float> m_fBorderFadeAnimationProgress; PHLANIMVAR<float> m_borderFadeAnimationProgress;
PHLANIMVAR<float> m_fBorderAngleAnimationProgress; PHLANIMVAR<float> m_borderAngleAnimationProgress;
// Fade in-out // Fade in-out
PHLANIMVAR<float> m_fAlpha; PHLANIMVAR<float> m_alpha;
bool m_bFadingOut = false; bool m_fadingOut = false;
bool m_bReadyToDelete = false; bool m_readyToDelete = false;
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in Vector2D m_originalClosedPos; // these will be used for calculations later on in
Vector2D m_vOriginalClosedSize; // drawing the closing animations Vector2D m_originalClosedSize; // drawing the closing animations
SBoxExtents m_eOriginalClosedExtents; SBoxExtents m_originalClosedExtents;
bool m_bAnimatingIn = false; bool m_animatingIn = false;
// For pinned (sticky) windows // For pinned (sticky) windows
bool m_bPinned = false; bool m_pinned = false;
// For preserving pinned state when fullscreening a pinned window // For preserving pinned state when fullscreening a pinned window
bool m_bPinFullscreened = false; bool m_pinFullscreened = false;
// urgency hint // urgency hint
bool m_bIsUrgent = false; bool m_isUrgent = false;
// for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window. // for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window.
PHLWINDOWREF m_pLastCycledWindow; PHLWINDOWREF m_lastCycledWindow;
// Window decorations // Window decorations
// TODO: make this a SP. // TODO: make this a SP.
std::vector<UP<IHyprWindowDecoration>> m_dWindowDecorations; std::vector<UP<IHyprWindowDecoration>> m_windowDecorations;
std::vector<IHyprWindowDecoration*> m_vDecosToRemove; std::vector<IHyprWindowDecoration*> m_decosToRemove;
// Special render data, rules, etc // Special render data, rules, etc
SWindowData m_sWindowData; SWindowData m_windowData;
// Transformers // Transformers
std::vector<UP<IWindowTransformer>> m_vTransformers; std::vector<UP<IWindowTransformer>> m_transformers;
// for alpha // for alpha
PHLANIMVAR<float> m_fActiveInactiveAlpha; PHLANIMVAR<float> m_activeInactiveAlpha;
PHLANIMVAR<float> m_fMovingFromWorkspaceAlpha; PHLANIMVAR<float> m_movingFromWorkspaceAlpha;
// animated shadow color // animated shadow color
PHLANIMVAR<CHyprColor> m_cRealShadowColor; PHLANIMVAR<CHyprColor> m_realShadowColor;
// animated tint // animated tint
PHLANIMVAR<float> m_fDimPercent; PHLANIMVAR<float> m_dimPercent;
// animate moving to an invisible workspace // animate moving to an invisible workspace
int m_iMonitorMovedFrom = -1; // -1 means not moving int m_monitorMovedFrom = -1; // -1 means not moving
PHLANIMVAR<float> m_fMovingToWorkspaceAlpha; PHLANIMVAR<float> m_movingToWorkspaceAlpha;
// swallowing // swallowing
PHLWINDOWREF m_pSwallowed; PHLWINDOWREF m_swallowed;
bool m_bCurrentlySwallowed = false; bool m_currentlySwallowed = false;
bool m_bGroupSwallowed = false; bool m_groupSwallowed = false;
// focus stuff // focus stuff
bool m_bStayFocused = false; bool m_stayFocused = false;
// for toplevel monitor events // for toplevel monitor events
MONITORID m_iLastToplevelMonitorID = -1; MONITORID m_lastSurfaceMonitorID = -1;
MONITORID m_iLastSurfaceMonitorID = -1;
// for idle inhibiting windows // for idle inhibiting windows
eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE; eIdleInhibitMode m_idleInhibitMode = IDLEINHIBIT_NONE;
// initial token. Will be unregistered on workspace change or timeout of 2 minutes // initial token. Will be unregistered on workspace change or timeout of 2 minutes
std::string m_szInitialWorkspaceToken = ""; std::string m_initialWorkspaceToken = "";
// for groups // for groups
struct SGroupData { struct SGroupData {
@@ -379,13 +295,13 @@ class CWindow {
bool head = false; bool head = false;
bool locked = false; // per group lock bool locked = false; // per group lock
bool deny = false; // deny window from enter a group or made a group bool deny = false; // deny window from enter a group or made a group
} m_sGroupData; } m_groupData;
uint16_t m_eGroupRules = GROUP_NONE; uint16_t m_groupRules = GROUP_NONE;
bool m_bTearingHint = false; bool m_tearingHint = false;
// stores the currently matched window rules // stores the currently matched window rules
std::vector<SP<CWindowRule>> m_vMatchedRules; std::vector<SP<CWindowRule>> m_matchedRules;
// window tags // window tags
CTagKeeper m_tags; CTagKeeper m_tags;
@@ -393,10 +309,13 @@ class CWindow {
// ANR // ANR
PHLANIMVAR<float> m_notRespondingTint; PHLANIMVAR<float> m_notRespondingTint;
// For the noclosefor windowrule
Time::steady_tp m_closeableSince = Time::steadyNow();
// For the list lookup // For the list lookup
bool operator==(const CWindow& rhs) const { 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 && return m_xdgSurface == rhs.m_xdgSurface && m_xwaylandSurface == rhs.m_xwaylandSurface && m_position == rhs.m_position && m_size == rhs.m_size &&
m_bFadingOut == rhs.m_bFadingOut; m_fadingOut == rhs.m_fadingOut;
} }
// methods // methods
@@ -486,9 +405,12 @@ class CWindow {
void setContentType(NContentType::eContentType contentType); void setContentType(NContentType::eContentType contentType);
void deactivateGroupMembers(); void deactivateGroupMembers();
bool isNotResponding(); bool isNotResponding();
std::optional<std::string> xdgTag();
std::optional<std::string> xdgDescription();
PHLWINDOW parent();
CBox getWindowMainSurfaceBox() const { CBox getWindowMainSurfaceBox() const {
return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; return {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y};
} }
// listeners // listeners
@@ -498,7 +420,7 @@ class CWindow {
std::unordered_map<std::string, std::string> getEnv(); std::unordered_map<std::string, std::string> getEnv();
// //
PHLWINDOWREF m_pSelf; PHLWINDOWREF m_self;
// make private once we move listeners to inside CWindow // make private once we move listeners to inside CWindow
struct { struct {
@@ -513,13 +435,13 @@ class CWindow {
CHyprSignalListener updateState; CHyprSignalListener updateState;
CHyprSignalListener updateMetadata; CHyprSignalListener updateMetadata;
CHyprSignalListener resourceChange; CHyprSignalListener resourceChange;
} listeners; } m_listeners;
private: private:
// For hidden windows and stuff // For hidden windows and stuff
bool m_bHidden = false; bool m_hidden = false;
bool m_bSuspended = false; bool m_suspended = false;
WORKSPACEID m_iLastWorkspace = WORKSPACE_INVALID; WORKSPACEID m_lastWorkspace = WORKSPACE_INVALID;
}; };
inline bool valid(PHLWINDOW w) { inline bool valid(PHLWINDOW w) {
@@ -533,48 +455,49 @@ inline bool valid(PHLWINDOWREF w) {
inline bool validMapped(PHLWINDOW w) { inline bool validMapped(PHLWINDOW w) {
if (!valid(w)) if (!valid(w))
return false; return false;
return w->m_bIsMapped; return w->m_isMapped;
} }
inline bool validMapped(PHLWINDOWREF w) { inline bool validMapped(PHLWINDOWREF w) {
if (!valid(w)) if (!valid(w))
return false; return false;
return w->m_bIsMapped; return w->m_isMapped;
} }
namespace NWindowProperties { namespace NWindowProperties {
static const std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> boolWindowProperties = { static const std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(const PHLWINDOW&)>> boolWindowProperties = {
{"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.allowsInput; }}, {"allowsinput", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.allowsInput; }},
{"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.dimAround; }}, {"dimaround", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.dimAround; }},
{"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.decorate; }}, {"decorate", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.decorate; }},
{"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }}, {"focusonactivate", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.focusOnActivate; }},
{"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }}, {"keepaspectratio", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.keepAspectRatio; }},
{"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }}, {"nearestneighbor", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.nearestNeighbor; }},
{"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noAnim; }}, {"noanim", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noAnim; }},
{"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBlur; }}, {"noblur", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noBlur; }},
{"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noBorder; }}, {"noborder", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noBorder; }},
{"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noDim; }}, {"nodim", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noDim; }},
{"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noFocus; }}, {"nofocus", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noFocus; }},
{"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noMaxSize; }}, {"nomaxsize", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noMaxSize; }},
{"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noRounding; }}, {"norounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noRounding; }},
{"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShadow; }}, {"noshadow", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noShadow; }},
{"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }}, {"noshortcutsinhibit", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noShortcutsInhibit; }},
{"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.opaque; }}, {"opaque", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.opaque; }},
{"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.RGBX; }}, {"forcergbx", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.RGBX; }},
{"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }}, {"syncfullscreen", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.syncFullscreen; }},
{"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.tearing; }}, {"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.tearing; }},
{"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.xray; }}, {"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.xray; }},
{"nofollowmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noFollowMouse; }},
}; };
const std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(const PHLWINDOW&)>> intWindowProperties = { const std::unordered_map<std::string, std::function<CWindowOverridableVar<Hyprlang::INT>*(const PHLWINDOW&)>> intWindowProperties = {
{"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"rounding", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.rounding; }},
{"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.borderSize; }}, {"bordersize", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.borderSize; }},
}; };
const std::unordered_map<std::string, std::function<CWindowOverridableVar<float>*(PHLWINDOW)>> floatWindowProperties = { const std::unordered_map<std::string, std::function<CWindowOverridableVar<Hyprlang::FLOAT>*(PHLWINDOW)>> floatWindowProperties = {
{"roundingpower", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.roundingPower; }}, {"roundingpower", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.roundingPower; }},
{"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }}, {"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.scrollMouse; }},
{"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}, {"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.scrollTouchpad; }},
}; };
}; };
@@ -608,13 +531,13 @@ struct std::formatter<PHLWINDOW, CharT> : std::formatter<CharT> {
return std::format_to(out, "[Window nullptr]"); return std::format_to(out, "[Window nullptr]");
std::format_to(out, "["); std::format_to(out, "[");
std::format_to(out, "Window {:x}: title: \"{}\"", (uintptr_t)w.get(), w->m_szTitle); std::format_to(out, "Window {:x}: title: \"{}\"", (uintptr_t)w.get(), w->m_title);
if (formatWorkspace) if (formatWorkspace)
std::format_to(out, ", workspace: {}", w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID); std::format_to(out, ", workspace: {}", w->m_workspace ? w->workspaceID() : WORKSPACE_INVALID);
if (formatMonitor) if (formatMonitor)
std::format_to(out, ", monitor: {}", w->monitorID()); std::format_to(out, ", monitor: {}", w->monitorID());
if (formatClass) if (formatClass)
std::format_to(out, ", class: {}", w->m_szClass); std::format_to(out, ", class: {}", w->m_class);
return std::format_to(out, "]"); return std::format_to(out, "]");
} }
}; };

View File

@@ -0,0 +1,132 @@
#pragma once
#include <cstdint>
#include <type_traits>
#include <any>
#include "../config/ConfigValue.hpp"
enum eOverridePriority : uint8_t {
PRIORITY_LAYOUT = 0,
PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP,
};
template <typename T>
T clampOptional(T const& value, std::optional<T> const& min, std::optional<T> const& max) {
return std::clamp(value, min.value_or(std::numeric_limits<T>::min()), max.value_or(std::numeric_limits<T>::max()));
}
template <typename T, bool Extended = std::is_same_v<T, bool> || std::is_same_v<T, Hyprlang::INT> || std::is_same_v<T, Hyprlang::FLOAT>>
class CWindowOverridableVar {
public:
CWindowOverridableVar(T const& value, eOverridePriority priority) {
m_values[priority] = value;
}
CWindowOverridableVar(T const& value) : m_defaultValue{value} {}
CWindowOverridableVar(T const& value, std::optional<T> const& min, std::optional<T> const& max = std::nullopt) : m_defaultValue{value}, m_minValue{min}, m_maxValue{max} {}
CWindowOverridableVar(std::string const& value)
requires(Extended && !std::is_same_v<T, bool>)
: m_configValue(SP<CConfigValue<T>>(new CConfigValue<T>(value))) {}
CWindowOverridableVar(std::string const& value, std::optional<T> const& min, std::optional<T> const& max = std::nullopt)
requires(Extended && !std::is_same_v<T, bool>)
: m_minValue(min), m_maxValue(max), m_configValue(SP<CConfigValue<T>>(new CConfigValue<T>(value))) {}
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default;
CWindowOverridableVar& operator=(CWindowOverridableVar<T> const& other) {
// Self-assignment check
if (this == &other)
return *this;
for (auto const& value : other.m_values) {
if constexpr (Extended && !std::is_same_v<T, bool>)
m_values[value.first] = clampOptional(value.second, m_minValue, m_maxValue);
else
m_values[value.first] = value.second;
}
return *this;
}
void unset(eOverridePriority priority) {
m_values.erase(priority);
}
bool hasValue() {
return !m_values.empty();
}
T value() {
if (!m_values.empty())
return std::prev(m_values.end())->second;
else
throw std::bad_optional_access();
}
T valueOr(T const& other) {
if (hasValue())
return value();
else
return other;
}
T valueOrDefault()
requires(Extended && !std::is_same_v<T, bool>)
{
if (hasValue())
return value();
else if (m_defaultValue.has_value())
return m_defaultValue.value();
else
return **std::any_cast<SP<CConfigValue<T>>>(m_configValue);
}
T valueOrDefault()
requires(!Extended || std::is_same_v<T, bool>)
{
if (hasValue())
return value();
else if (!m_defaultValue.has_value())
throw std::bad_optional_access();
else
return m_defaultValue.value();
}
eOverridePriority getPriority() {
if (!m_values.empty())
return std::prev(m_values.end())->first;
else
throw std::bad_optional_access();
}
void increment(T const& other, eOverridePriority priority) {
if constexpr (std::is_same_v<T, bool>)
m_values[priority] = valueOr(false) ^ other;
else
m_values[priority] = clampOptional(valueOrDefault() + other, m_minValue, m_maxValue);
}
void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
if (optValue.has_value())
m_values[priority] = optValue.value();
else
unset(priority);
}
operator std::optional<T>() {
if (hasValue())
return value();
else
return std::nullopt;
}
private:
std::map<eOverridePriority, T> m_values;
std::optional<T> m_defaultValue; // used for toggling, so required for bool
std::optional<T> m_minValue;
std::optional<T> m_maxValue;
std::any m_configValue; // only there for select variables
};

View File

@@ -8,89 +8,90 @@ static const auto RULES = std::unordered_set<std::string>{
"float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", "persistentsize", "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", "persistentsize",
}; };
static const auto RULES_PREFIX = std::unordered_set<std::string>{ static const auto RULES_PREFIX = std::unordered_set<std::string>{
"animation", "bordercolor", "bordersize", "center", "content", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "animation", "bordercolor", "bordersize", "center", "content", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor",
"monitor", "move", "opacity", "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", "move", "noclosefor", "opacity", "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", "size",
"size", "suppressevent", "tag", "workspace", "xray", "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) { CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : m_value(value), m_rule(rule), m_v2(isV2), m_execRule(isExecRule) {
const auto VALS = CVarList(rule, 2, ' '); 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); }) || const bool VALID = RULES.contains(rule) || std::ranges::any_of(RULES_PREFIX, [&rule](auto prefix) { return rule.starts_with(prefix); }) ||
(NWindowProperties::boolWindowProperties.find(VALS[0]) != NWindowProperties::boolWindowProperties.end()) || (NWindowProperties::boolWindowProperties.contains(VALS[0])) || (NWindowProperties::intWindowProperties.contains(VALS[0])) ||
(NWindowProperties::intWindowProperties.find(VALS[0]) != NWindowProperties::intWindowProperties.end()) || (NWindowProperties::floatWindowProperties.contains(VALS[0]));
(NWindowProperties::floatWindowProperties.find(VALS[0]) != NWindowProperties::floatWindowProperties.end());
if (!VALID) if (!VALID)
return; return;
if (rule == "float") if (rule == "float")
ruleType = RULE_FLOAT; m_ruleType = RULE_FLOAT;
else if (rule == "fullscreen") else if (rule == "fullscreen")
ruleType = RULE_FULLSCREEN; m_ruleType = RULE_FULLSCREEN;
else if (rule == "maximize") else if (rule == "maximize")
ruleType = RULE_MAXIMIZE; m_ruleType = RULE_MAXIMIZE;
else if (rule == "noinitialfocus") else if (rule == "noinitialfocus")
ruleType = RULE_NOINITIALFOCUS; m_ruleType = RULE_NOINITIALFOCUS;
else if (rule == "pin") else if (rule == "pin")
ruleType = RULE_PIN; m_ruleType = RULE_PIN;
else if (rule == "stayfocused") else if (rule == "stayfocused")
ruleType = RULE_STAYFOCUSED; m_ruleType = RULE_STAYFOCUSED;
else if (rule == "tile") else if (rule == "tile")
ruleType = RULE_TILE; m_ruleType = RULE_TILE;
else if (rule == "renderunfocused") else if (rule == "renderunfocused")
ruleType = RULE_RENDERUNFOCUSED; m_ruleType = RULE_RENDERUNFOCUSED;
else if (rule == "persistentsize") else if (rule == "persistentsize")
ruleType = RULE_PERSISTENTSIZE; m_ruleType = RULE_PERSISTENTSIZE;
else if (rule.starts_with("animation")) else if (rule.starts_with("animation"))
ruleType = RULE_ANIMATION; m_ruleType = RULE_ANIMATION;
else if (rule.starts_with("bordercolor")) else if (rule.starts_with("bordercolor"))
ruleType = RULE_BORDERCOLOR; m_ruleType = RULE_BORDERCOLOR;
else if (rule.starts_with("center")) else if (rule.starts_with("center"))
ruleType = RULE_CENTER; m_ruleType = RULE_CENTER;
else if (rule.starts_with("fullscreenstate")) else if (rule.starts_with("fullscreenstate"))
ruleType = RULE_FULLSCREENSTATE; m_ruleType = RULE_FULLSCREENSTATE;
else if (rule.starts_with("group")) else if (rule.starts_with("group"))
ruleType = RULE_GROUP; m_ruleType = RULE_GROUP;
else if (rule.starts_with("idleinhibit")) else if (rule.starts_with("idleinhibit"))
ruleType = RULE_IDLEINHIBIT; m_ruleType = RULE_IDLEINHIBIT;
else if (rule.starts_with("maxsize")) else if (rule.starts_with("maxsize"))
ruleType = RULE_MAXSIZE; m_ruleType = RULE_MAXSIZE;
else if (rule.starts_with("minsize")) else if (rule.starts_with("minsize"))
ruleType = RULE_MINSIZE; m_ruleType = RULE_MINSIZE;
else if (rule.starts_with("monitor")) else if (rule.starts_with("monitor"))
ruleType = RULE_MONITOR; m_ruleType = RULE_MONITOR;
else if (rule.starts_with("move")) else if (rule.starts_with("move"))
ruleType = RULE_MOVE; m_ruleType = RULE_MOVE;
else if (rule.starts_with("opacity")) else if (rule.starts_with("opacity"))
ruleType = RULE_OPACITY; m_ruleType = RULE_OPACITY;
else if (rule.starts_with("plugin:")) else if (rule.starts_with("plugin:"))
ruleType = RULE_PLUGIN; m_ruleType = RULE_PLUGIN;
else if (rule.starts_with("pseudo")) else if (rule.starts_with("pseudo"))
ruleType = RULE_PSEUDO; m_ruleType = RULE_PSEUDO;
else if (rule.starts_with("size")) else if (rule.starts_with("size"))
ruleType = RULE_SIZE; m_ruleType = RULE_SIZE;
else if (rule.starts_with("suppressevent")) else if (rule.starts_with("suppressevent"))
ruleType = RULE_SUPPRESSEVENT; m_ruleType = RULE_SUPPRESSEVENT;
else if (rule.starts_with("tag")) else if (rule.starts_with("tag"))
ruleType = RULE_TAG; m_ruleType = RULE_TAG;
else if (rule.starts_with("workspace")) else if (rule.starts_with("workspace"))
ruleType = RULE_WORKSPACE; m_ruleType = RULE_WORKSPACE;
else if (rule.starts_with("prop")) else if (rule.starts_with("prop"))
ruleType = RULE_PROP; m_ruleType = RULE_PROP;
else if (rule.starts_with("content")) else if (rule.starts_with("content"))
ruleType = RULE_CONTENT; m_ruleType = RULE_CONTENT;
else if (rule.starts_with("noclosefor"))
m_ruleType = RULE_NOCLOSEFOR;
else { else {
// check if this is a prop. // check if this is a prop.
const CVarList VARS(rule, 0, 's', true); const CVarList VARS(rule, 0, 's', true);
if (NWindowProperties::intWindowProperties.find(VARS[0]) != NWindowProperties::intWindowProperties.end() || const bool ISPROP = NWindowProperties::intWindowProperties.contains(VARS[0]) || NWindowProperties::boolWindowProperties.contains(VARS[0]) ||
NWindowProperties::boolWindowProperties.find(VARS[0]) != NWindowProperties::boolWindowProperties.end() || NWindowProperties::floatWindowProperties.contains(VARS[0]);
NWindowProperties::floatWindowProperties.find(VARS[0]) != NWindowProperties::floatWindowProperties.end()) { if (ISPROP) {
*const_cast<std::string*>(&szRule) = "prop " + rule; *const_cast<std::string*>(&m_rule) = "prop " + rule;
ruleType = RULE_PROP; m_ruleType = RULE_PROP;
Debug::log(LOG, "CWindowRule: direct prop rule found, rewritten {} -> {}", rule, szRule); Debug::log(LOG, "CWindowRule: direct prop rule found, rewritten {} -> {}", rule, m_rule);
} else { } else {
Debug::log(ERR, "CWindowRule: didn't match a rule that was found valid?!"); Debug::log(ERR, "CWindowRule: didn't match a rule that was found valid?!");
ruleType = RULE_INVALID; m_ruleType = RULE_INVALID;
} }
} }
} }

View File

@@ -38,34 +38,36 @@ class CWindowRule {
RULE_PROP, RULE_PROP,
RULE_CONTENT, RULE_CONTENT,
RULE_PERSISTENTSIZE, RULE_PERSISTENTSIZE,
RULE_NOCLOSEFOR,
}; };
eRuleType ruleType = RULE_INVALID; eRuleType m_ruleType = RULE_INVALID;
const std::string szValue; const std::string m_value;
const std::string szRule; const std::string m_rule;
const bool v2 = false; const bool m_v2 = false;
const bool execRule = false; const bool m_execRule = false;
std::string szTitle; std::string m_title;
std::string szClass; std::string m_class;
std::string szInitialTitle; std::string m_initialTitle;
std::string szInitialClass; std::string m_initialClass;
std::string szTag; std::string m_tag;
int bX11 = -1; // -1 means "ANY" int m_X11 = -1; // -1 means "ANY"
int bFloating = -1; int m_floating = -1;
int bFullscreen = -1; int m_fullscreen = -1;
int bPinned = -1; int m_pinned = -1;
int bFocus = -1; int m_focus = -1;
std::string szFullscreenState = ""; // empty means any std::string m_fullscreenState = ""; // empty means any
std::string szOnWorkspace = ""; // empty means any std::string m_onWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any std::string m_workspace = ""; // empty means any
std::string szContentType = ""; // empty means any std::string m_contentType = ""; // empty means any
std::string m_xdgTag = ""; // empty means any
// precompiled regexes // precompiled regexes
CRuleRegexContainer rTitle; CRuleRegexContainer m_titleRegex;
CRuleRegexContainer rClass; CRuleRegexContainer m_classRegex;
CRuleRegexContainer rInitialTitle; CRuleRegexContainer m_initialTitleRegex;
CRuleRegexContainer rInitialClass; CRuleRegexContainer m_initialClassRegex;
CRuleRegexContainer rV1Regex; CRuleRegexContainer m_v1Regex;
}; };

View File

@@ -17,76 +17,76 @@ PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string
} }
CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool 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) { m_id(id), m_name(name), m_monitor(monitor), m_isSpecialWorkspace(special), m_wasCreatedEmpty(isEmpty) {
; ;
} }
void CWorkspace::init(PHLWORKSPACE self) { void CWorkspace::init(PHLWORKSPACE self) {
m_pSelf = self; m_self = self;
g_pAnimationManager->createAnimation(Vector2D(0, 0), m_vRenderOffset, g_pAnimationManager->createAnimation(Vector2D(0, 0), m_renderOffset, g_pConfigManager->getAnimationPropertyConfig(m_isSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"),
g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, AVARDAMAGE_ENTIRE); self, AVARDAMAGE_ENTIRE);
g_pAnimationManager->createAnimation(1.f, m_fAlpha, g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, g_pAnimationManager->createAnimation(1.f, m_alpha, g_pConfigManager->getAnimationPropertyConfig(m_isSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self,
AVARDAMAGE_ENTIRE); AVARDAMAGE_ENTIRE);
const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self); const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self);
if (RULEFORTHIS.defaultName.has_value()) if (RULEFORTHIS.defaultName.has_value())
m_szName = RULEFORTHIS.defaultName.value(); m_name = RULEFORTHIS.defaultName.value();
m_pFocusedWindowHook = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any param) { m_focusedWindowHook = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any param) {
const auto PWINDOW = std::any_cast<PHLWINDOW>(param); const auto PWINDOW = std::any_cast<PHLWINDOW>(param);
if (PWINDOW == m_pLastFocusedWindow.lock()) if (PWINDOW == m_lastFocusedWindow.lock())
m_pLastFocusedWindow.reset(); m_lastFocusedWindow.reset();
}); });
m_bInert = false; m_inert = false;
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self);
m_bPersistent = WORKSPACERULE.isPersistent; m_persistent = WORKSPACERULE.isPersistent;
if (self->m_bWasCreatedEmpty) if (self->m_wasCreatedEmpty)
if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd)
g_pKeybindManager->spawnWithRules(*cmd, self); CKeybindManager::spawnWithRules(*cmd, self);
g_pEventManager->postEvent({"createworkspace", m_szName}); g_pEventManager->postEvent({.event = "createworkspace", .data = m_name});
g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)}); g_pEventManager->postEvent({.event = "createworkspacev2", .data = std::format("{},{}", m_id, m_name)});
EMIT_HOOK_EVENT("createWorkspace", this); EMIT_HOOK_EVENT("createWorkspace", this);
} }
SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName() const { SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName() const {
return m_sPrevWorkspace; return m_prevWorkspace;
} }
CWorkspace::~CWorkspace() { CWorkspace::~CWorkspace() {
Debug::log(LOG, "Destroying workspace ID {}", m_iID); Debug::log(LOG, "Destroying workspace ID {}", m_id);
// check if g_pHookSystem and g_pEventManager exist, they might be destroyed as in when the compositor is closing. // check if g_pHookSystem and g_pEventManager exist, they might be destroyed as in when the compositor is closing.
if (g_pHookSystem) if (g_pHookSystem)
g_pHookSystem->unhook(m_pFocusedWindowHook); g_pHookSystem->unhook(m_focusedWindowHook);
if (g_pEventManager) { if (g_pEventManager) {
g_pEventManager->postEvent({"destroyworkspace", m_szName}); g_pEventManager->postEvent({.event = "destroyworkspace", .data = m_name});
g_pEventManager->postEvent({"destroyworkspacev2", std::format("{},{}", m_iID, m_szName)}); g_pEventManager->postEvent({.event = "destroyworkspacev2", .data = std::format("{},{}", m_id, m_name)});
EMIT_HOOK_EVENT("destroyWorkspace", this); EMIT_HOOK_EVENT("destroyWorkspace", this);
} }
} }
void CWorkspace::startAnim(bool in, bool left, bool instant) { void CWorkspace::startAnim(bool in, bool left, bool instant) {
if (!instant) { if (!instant) {
const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out"); const std::string ANIMNAME = std::format("{}{}", m_isSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out");
m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME));
m_vRenderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); m_renderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME));
} }
const auto ANIMSTYLE = m_fAlpha->getStyle(); const auto ANIMSTYLE = m_alpha->getStyle();
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
// set floating windows offset callbacks // set floating windows offset callbacks
m_vRenderOffset->setUpdateCallback([&](auto) { m_renderOffset->setUpdateCallback([&](auto) {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (!validMapped(w) || w->workspaceID() != m_iID) if (!validMapped(w) || w->workspaceID() != m_id)
continue; continue;
w->onWorkspaceAnimUpdate(); w->onWorkspaceAnimUpdate();
@@ -94,7 +94,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
}); });
if (ANIMSTYLE.starts_with("slidefade")) { if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_monitor.lock();
float movePerc = 100.f; float movePerc = 100.f;
if (ANIMSTYLE.find('%') != std::string::npos) { if (ANIMSTYLE.find('%') != std::string::npos) {
@@ -104,84 +104,84 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
} catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); } } catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); }
} }
m_fAlpha->setValueAndWarp(1.f); m_alpha->setValueAndWarp(1.f);
m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); m_renderOffset->setValueAndWarp(Vector2D(0, 0));
if (ANIMSTYLE.starts_with("slidefadevert")) { if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) { if (in) {
m_fAlpha->setValueAndWarp(0.f); m_alpha->setValueAndWarp(0.f);
m_vRenderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); m_renderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->m_size.y : -PMONITOR->m_size.y) * (movePerc / 100.f)));
*m_fAlpha = 1.f; *m_alpha = 1.f;
*m_vRenderOffset = Vector2D(0, 0); *m_renderOffset = Vector2D(0, 0);
} else { } else {
m_fAlpha->setValueAndWarp(1.f); m_alpha->setValueAndWarp(1.f);
*m_fAlpha = 0.f; *m_alpha = 0.f;
*m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); *m_renderOffset = Vector2D(0.0, (left ? -PMONITOR->m_size.y : PMONITOR->m_size.y) * (movePerc / 100.f));
} }
} else { } else {
if (in) { if (in) {
m_fAlpha->setValueAndWarp(0.f); m_alpha->setValueAndWarp(0.f);
m_vRenderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0)); m_renderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->m_size.x : -PMONITOR->m_size.x) * (movePerc / 100.f), 0.0));
*m_fAlpha = 1.f; *m_alpha = 1.f;
*m_vRenderOffset = Vector2D(0, 0); *m_renderOffset = Vector2D(0, 0);
} else { } else {
m_fAlpha->setValueAndWarp(1.f); m_alpha->setValueAndWarp(1.f);
*m_fAlpha = 0.f; *m_alpha = 0.f;
*m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0); *m_renderOffset = Vector2D((left ? -PMONITOR->m_size.x : PMONITOR->m_size.x) * (movePerc / 100.f), 0.0);
} }
} }
} else if (ANIMSTYLE == "fade") { } else if (ANIMSTYLE == "fade") {
m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade. m_renderOffset->setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade.
if (in) { if (in) {
m_fAlpha->setValueAndWarp(0.f); m_alpha->setValueAndWarp(0.f);
*m_fAlpha = 1.f; *m_alpha = 1.f;
} else { } else {
m_fAlpha->setValueAndWarp(1.f); m_alpha->setValueAndWarp(1.f);
*m_fAlpha = 0.f; *m_alpha = 0.f;
} }
} else if (ANIMSTYLE == "slidevert") { } else if (ANIMSTYLE == "slidevert") {
// fallback is slide // fallback is slide
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_monitor.lock();
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP; const auto YDISTANCE = PMONITOR->m_size.y + *PWORKSPACEGAP;
m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_alpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) { if (in) {
m_vRenderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE)); m_renderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
*m_vRenderOffset = Vector2D(0, 0); *m_renderOffset = Vector2D(0, 0);
} else { } else {
*m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE); *m_renderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
} }
} else { } else {
// fallback is slide // fallback is slide
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_monitor.lock();
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP; const auto XDISTANCE = PMONITOR->m_size.x + *PWORKSPACEGAP;
m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_alpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) { if (in) {
m_vRenderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0)); m_renderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
*m_vRenderOffset = Vector2D(0, 0); *m_renderOffset = Vector2D(0, 0);
} else { } else {
*m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0); *m_renderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
} }
} }
if (m_bIsSpecialWorkspace) { if (m_isSpecialWorkspace) {
// required for open/close animations // required for open/close animations
if (in) { if (in) {
m_fAlpha->setValueAndWarp(0.f); m_alpha->setValueAndWarp(0.f);
*m_fAlpha = 1.f; *m_alpha = 1.f;
} else { } else {
m_fAlpha->setValueAndWarp(1.f); m_alpha->setValueAndWarp(1.f);
*m_fAlpha = 0.f; *m_alpha = 0.f;
} }
} }
if (instant) { if (instant) {
m_vRenderOffset->warp(); m_renderOffset->warp();
m_fAlpha->warp(); m_alpha->warp();
} }
} }
@@ -194,39 +194,39 @@ void CWorkspace::moveToMonitor(const MONITORID& id) {
} }
PHLWINDOW CWorkspace::getLastFocusedWindow() { PHLWINDOW CWorkspace::getLastFocusedWindow() {
if (!validMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow->workspaceID() != m_iID) if (!validMapped(m_lastFocusedWindow) || m_lastFocusedWindow->workspaceID() != m_id)
return nullptr; return nullptr;
return m_pLastFocusedWindow.lock(); return m_lastFocusedWindow.lock();
} }
void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) { void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
if (!prev) { if (!prev) {
m_sPrevWorkspace.id = -1; m_prevWorkspace.id = -1;
m_sPrevWorkspace.name = ""; m_prevWorkspace.name = "";
return; return;
} }
if (prev->m_iID == m_iID) { if (prev->m_id == m_id) {
Debug::log(LOG, "Tried to set prev workspace to the same as current one"); Debug::log(LOG, "Tried to set prev workspace to the same as current one");
return; return;
} }
m_sPrevWorkspace.id = prev->m_iID; m_prevWorkspace.id = prev->m_id;
m_sPrevWorkspace.name = prev->m_szName; m_prevWorkspace.name = prev->m_name;
prev->m_pMonitor->addPrevWorkspaceID(prev->m_iID); prev->m_monitor->addPrevWorkspaceID(prev->m_id);
} }
std::string CWorkspace::getConfigName() { std::string CWorkspace::getConfigName() {
if (m_bIsSpecialWorkspace) { if (m_isSpecialWorkspace) {
return m_szName; return m_name;
} }
if (m_iID > 0) if (m_id > 0)
return std::to_string(m_iID); return std::to_string(m_id);
return "name:" + m_szName; return "name:" + m_name;
} }
bool CWorkspace::matchesStaticSelector(const std::string& selector_) { bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
@@ -241,12 +241,12 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
if (wsid == WORKSPACE_INVALID) if (wsid == WORKSPACE_INVALID)
return false; return false;
return wsid == m_iID; return wsid == m_id;
} else if (selector.starts_with("name:")) { } else if (selector.starts_with("name:")) {
return m_szName == selector.substr(5); return m_name == selector.substr(5);
} else if (selector.starts_with("special")) { } else if (selector.starts_with("special")) {
return m_szName == selector; return m_name == selector;
} else { } else {
// parse selector // parse selector
@@ -306,7 +306,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false; return false;
} }
if (std::clamp(m_iID, from, to) != m_iID) if (std::clamp(m_id, from, to) != m_id)
return false; return false;
continue; continue;
} }
@@ -321,7 +321,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto SHOULDBESPECIAL = configStringToInt(prop); const auto SHOULDBESPECIAL = configStringToInt(prop);
if (SHOULDBESPECIAL && (bool)*SHOULDBESPECIAL != m_bIsSpecialWorkspace) if (SHOULDBESPECIAL && (bool)*SHOULDBESPECIAL != m_isSpecialWorkspace)
return false; return false;
continue; continue;
} }
@@ -336,7 +336,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
const auto PMONITOR = g_pCompositor->getMonitorFromString(prop); const auto PMONITOR = g_pCompositor->getMonitorFromString(prop);
if (!(PMONITOR ? PMONITOR == m_pMonitor : false)) if (!(PMONITOR ? PMONITOR == m_monitor : false))
return false; return false;
continue; continue;
} }
@@ -349,14 +349,14 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
prop = prop.substr(2, prop.length() - 3); prop = prop.substr(2, prop.length() - 3);
if (prop.starts_with("s:") && !m_szName.starts_with(prop.substr(2))) if (prop.starts_with("s:") && !m_name.starts_with(prop.substr(2)))
return false; return false;
if (prop.starts_with("e:") && !m_szName.ends_with(prop.substr(2))) if (prop.starts_with("e:") && !m_name.ends_with(prop.substr(2)))
return false; return false;
const auto WANTSNAMED = configStringToInt(prop); const auto WANTSNAMED = configStringToInt(prop);
if (WANTSNAMED && *WANTSNAMED != (m_iID <= -1337)) if (WANTSNAMED && *WANTSNAMED != (m_id <= -1337))
return false; return false;
continue; continue;
} }
@@ -481,15 +481,15 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
switch (FSSTATE) { switch (FSSTATE) {
case -1: // no fullscreen case -1: // no fullscreen
if (m_bHasFullscreenWindow) if (m_hasFullscreenWindow)
return false; return false;
break; break;
case 0: // fullscreen full case 0: // fullscreen full
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_FULLSCREEN) if (!m_hasFullscreenWindow || m_fullscreenMode != FSMODE_FULLSCREEN)
return false; return false;
break; break;
case 1: // maximized case 1: // maximized
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_MAXIMIZED) if (!m_hasFullscreenWindow || m_fullscreenMode != FSMODE_MAXIMIZED)
return false; return false;
break; break;
default: break; default: break;
@@ -509,23 +509,23 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
} }
void CWorkspace::markInert() { void CWorkspace::markInert() {
m_bInert = true; m_inert = true;
m_iID = WORKSPACE_INVALID; m_id = WORKSPACE_INVALID;
m_bVisible = false; m_visible = false;
m_pMonitor.reset(); m_monitor.reset();
} }
bool CWorkspace::inert() { bool CWorkspace::inert() {
return m_bInert; return m_inert;
} }
MONITORID CWorkspace::monitorID() { MONITORID CWorkspace::monitorID() {
return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID; return m_monitor ? m_monitor->m_id : MONITOR_INVALID;
} }
PHLWINDOW CWorkspace::getFullscreenWindow() { PHLWINDOW CWorkspace::getFullscreenWindow() {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (w->m_pWorkspace == m_pSelf && w->isFullscreen()) if (w->m_workspace == m_self && w->isFullscreen())
return w; return w;
} }
@@ -533,25 +533,25 @@ PHLWINDOW CWorkspace::getFullscreenWindow() {
} }
bool CWorkspace::isVisible() { bool CWorkspace::isVisible() {
return m_bVisible; return m_visible;
} }
bool CWorkspace::isVisibleNotCovered() { bool CWorkspace::isVisibleNotCovered() {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_monitor.lock();
if (PMONITOR->activeSpecialWorkspace) if (PMONITOR->m_activeSpecialWorkspace)
return PMONITOR->activeSpecialWorkspace->m_iID == m_iID; return PMONITOR->m_activeSpecialWorkspace->m_id == m_id;
return PMONITOR->activeWorkspace->m_iID == m_iID; return PMONITOR->m_activeWorkspace->m_id == m_id;
} }
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) { int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) {
int no = 0; int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped) if (w->workspaceID() != m_id || !w->m_isMapped)
continue; continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) if (onlyTiled.has_value() && w->m_isFloating == onlyTiled.value())
continue; continue;
if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value()) if (onlyPinned.has_value() && w->m_pinned != onlyPinned.value())
continue; continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue; continue;
@@ -563,14 +563,14 @@ int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> on
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) { int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) {
int no = 0; int no = 0;
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (w->workspaceID() != m_iID || !w->m_bIsMapped) if (w->workspaceID() != m_id || !w->m_isMapped)
continue; continue;
if (!w->m_sGroupData.head) if (!w->m_groupData.head)
continue; continue;
if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) if (onlyTiled.has_value() && w->m_isFloating == onlyTiled.value())
continue; continue;
if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value()) if (onlyPinned.has_value() && w->m_pinned != onlyPinned.value())
continue; continue;
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
continue; continue;
@@ -580,8 +580,8 @@ int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onl
} }
PHLWINDOW CWorkspace::getFirstWindow() { PHLWINDOW CWorkspace::getFirstWindow() {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && !w->isHidden()) if (w->m_workspace == m_self && w->m_isMapped && !w->isHidden())
return w; return w;
} }
@@ -589,32 +589,27 @@ PHLWINDOW CWorkspace::getFirstWindow() {
} }
PHLWINDOW CWorkspace::getTopLeftWindow() { PHLWINDOW CWorkspace::getTopLeftWindow() {
const auto PMONITOR = m_pMonitor.lock(); const auto PMONITOR = m_monitor.lock();
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) if (w->m_workspace != m_self || !w->m_isMapped || w->isHidden())
continue; continue;
const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
if (WINDOWIDEALBB.x <= PMONITOR->vecPosition.x + 1 && WINDOWIDEALBB.y <= PMONITOR->vecPosition.y + 1) if (WINDOWIDEALBB.x <= PMONITOR->m_position.x + 1 && WINDOWIDEALBB.y <= PMONITOR->m_position.y + 1)
return w; return w;
} }
return nullptr; return nullptr;
} }
bool CWorkspace::hasUrgentWindow() { bool CWorkspace::hasUrgentWindow() {
for (auto const& w : g_pCompositor->m_vWindows) { return std::ranges::any_of(g_pCompositor->m_windows, [this](const auto& w) { return w->m_workspace == m_self && w->m_isMapped && w->m_isUrgent; });
if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && w->m_bIsUrgent)
return true;
}
return false;
} }
void CWorkspace::updateWindowDecos() { void CWorkspace::updateWindowDecos() {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (w->m_pWorkspace != m_pSelf) if (w->m_workspace != m_self)
continue; continue;
w->updateWindowDecos(); w->updateWindowDecos();
@@ -622,10 +617,10 @@ void CWorkspace::updateWindowDecos() {
} }
void CWorkspace::updateWindowData() { void CWorkspace::updateWindowData() {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock()); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_self.lock());
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (w->m_pWorkspace != m_pSelf) if (w->m_workspace != m_self)
continue; continue;
w->updateWindowData(WORKSPACERULE); w->updateWindowData(WORKSPACERULE);
@@ -633,8 +628,8 @@ void CWorkspace::updateWindowData() {
} }
void CWorkspace::forceReportSizesToWindows() { void CWorkspace::forceReportSizesToWindows() {
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) if (w->m_workspace != m_self || !w->m_isMapped || w->isHidden())
continue; continue;
w->sendWindowSize(true); w->sendWindowSize(true);
@@ -642,26 +637,26 @@ void CWorkspace::forceReportSizesToWindows() {
} }
void CWorkspace::rename(const std::string& name) { void CWorkspace::rename(const std::string& name) {
if (g_pCompositor->isWorkspaceSpecial(m_iID)) if (g_pCompositor->isWorkspaceSpecial(m_id))
return; return;
Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name); Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_id, name);
m_szName = name; m_name = name;
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock()); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_self.lock());
m_bPersistent = WORKSPACERULE.isPersistent; m_persistent = WORKSPACERULE.isPersistent;
if (WORKSPACERULE.isPersistent) if (WORKSPACERULE.isPersistent)
g_pCompositor->ensurePersistentWorkspacesPresent(std::vector<SWorkspaceRule>{WORKSPACERULE}, m_pSelf.lock()); g_pCompositor->ensurePersistentWorkspacesPresent(std::vector<SWorkspaceRule>{WORKSPACERULE}, m_self.lock());
g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName}); g_pEventManager->postEvent({.event = "renameworkspace", .data = std::to_string(m_id) + "," + m_name});
} }
void CWorkspace::updateWindows() { 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(); }); m_hasFullscreenWindow = std::ranges::any_of(g_pCompositor->m_windows, [this](const auto& w) { return w->m_isMapped && w->m_workspace == m_self && w->isFullscreen(); });
for (auto const& w : g_pCompositor->m_vWindows) { for (auto const& w : g_pCompositor->m_windows) {
if (!w->m_bIsMapped || w->m_pWorkspace != m_pSelf) if (!w->m_isMapped || w->m_workspace != m_self)
continue; continue;
w->updateDynamicRules(); w->updateDynamicRules();

View File

@@ -2,7 +2,6 @@
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include <string> #include <string>
#include "../defines.hpp"
#include "DesktopTypes.hpp" #include "DesktopTypes.hpp"
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
@@ -24,39 +23,39 @@ class CWorkspace {
// Workspaces ID-based have IDs > 0 // Workspaces ID-based have IDs > 0
// and workspaces name-based have IDs starting with -1337 // and workspaces name-based have IDs starting with -1337
WORKSPACEID m_iID = WORKSPACE_INVALID; WORKSPACEID m_id = WORKSPACE_INVALID;
std::string m_szName = ""; std::string m_name = "";
PHLMONITORREF m_pMonitor; PHLMONITORREF m_monitor;
bool m_bHasFullscreenWindow = false; bool m_hasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FSMODE_NONE; eFullscreenMode m_fullscreenMode = FSMODE_NONE;
wl_array m_wlrCoordinateArr; wl_array m_wlrCoordinateArr;
// for animations // for animations
PHLANIMVAR<Vector2D> m_vRenderOffset; PHLANIMVAR<Vector2D> m_renderOffset;
PHLANIMVAR<float> m_fAlpha; PHLANIMVAR<float> m_alpha;
bool m_bForceRendering = false; bool m_forceRendering = false;
// allows damage to propagate. // allows damage to propagate.
bool m_bVisible = false; bool m_visible = false;
// "scratchpad" // "scratchpad"
bool m_bIsSpecialWorkspace = false; bool m_isSpecialWorkspace = false;
// last window // last window
PHLWINDOWREF m_pLastFocusedWindow; PHLWINDOWREF m_lastFocusedWindow;
// user-set // user-set
bool m_bDefaultFloating = false; bool m_defaultFloating = false;
bool m_bDefaultPseudo = false; bool m_defaultPseudo = false;
// last monitor (used on reconnect) // last monitor (used on reconnect)
std::string m_szLastMonitor = ""; std::string m_lastMonitor = "";
bool m_bWasCreatedEmpty = true; bool m_wasCreatedEmpty = true;
bool m_bPersistent = false; bool m_persistent = false;
// Inert: destroyed and invalid. If this is true, release the ptr you have. // Inert: destroyed and invalid. If this is true, release the ptr you have.
bool inert(); bool inert();
@@ -88,11 +87,11 @@ class CWorkspace {
void init(PHLWORKSPACE self); void init(PHLWORKSPACE self);
// Previous workspace ID and name is stored during a workspace change, allowing travel // Previous workspace ID and name is stored during a workspace change, allowing travel
// to the previous workspace. // to the previous workspace.
SWorkspaceIDName m_sPrevWorkspace; SWorkspaceIDName m_prevWorkspace;
SP<HOOK_CALLBACK_FN> m_pFocusedWindowHook; SP<HOOK_CALLBACK_FN> m_focusedWindowHook;
bool m_bInert = true; bool m_inert = true;
WP<CWorkspace> m_pSelf; WP<CWorkspace> m_self;
}; };
inline bool valid(const PHLWORKSPACE& ref) { inline bool valid(const PHLWORKSPACE& ref) {

View File

@@ -34,7 +34,8 @@ class IHID {
struct { struct {
CSignal destroy; CSignal destroy;
} events; } m_events;
std::string deviceName, hlName; std::string m_deviceName;
std::string m_hlName;
}; };

View File

@@ -28,38 +28,38 @@ eHIDType IKeyboard::getType() {
} }
IKeyboard::~IKeyboard() { IKeyboard::~IKeyboard() {
events.destroy.emit(); m_events.destroy.emit();
clearManuallyAllocd(); clearManuallyAllocd();
} }
void IKeyboard::clearManuallyAllocd() { void IKeyboard::clearManuallyAllocd() {
if (xkbStaticState) if (m_xkbStaticState)
xkb_state_unref(xkbStaticState); xkb_state_unref(m_xkbStaticState);
if (xkbState) if (m_xkbState)
xkb_state_unref(xkbState); xkb_state_unref(m_xkbState);
if (xkbKeymap) if (m_xkbKeymap)
xkb_keymap_unref(xkbKeymap); xkb_keymap_unref(m_xkbKeymap);
if (xkbSymState) if (m_xkbSymState)
xkb_state_unref(xkbSymState); xkb_state_unref(m_xkbSymState);
xkbSymState = nullptr; m_xkbSymState = nullptr;
xkbKeymap = nullptr; m_xkbKeymap = nullptr;
xkbState = nullptr; m_xkbState = nullptr;
xkbStaticState = nullptr; m_xkbStaticState = nullptr;
xkbKeymapFD.reset(); m_xkbKeymapFD.reset();
} }
void IKeyboard::setKeymap(const SStringRuleNames& rules) { void IKeyboard::setKeymap(const SStringRuleNames& rules) {
if (keymapOverridden) { if (m_keymapOverridden) {
Debug::log(LOG, "Ignoring setKeymap: keymap is overridden"); Debug::log(LOG, "Ignoring setKeymap: keymap is overridden");
return; return;
} }
currentRules = rules; m_currentRules = rules;
xkb_rule_names XKBRULES = { xkb_rule_names XKBRULES = {
.rules = rules.rules.c_str(), .rules = rules.rules.c_str(),
.model = rules.model.c_str(), .model = rules.model.c_str(),
@@ -80,21 +80,21 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model, Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model,
rules.options); rules.options);
if (!xkbFilePath.empty()) { if (!m_xkbFilePath.empty()) {
auto path = absolutePath(xkbFilePath, g_pConfigManager->configCurrentPath); auto path = absolutePath(m_xkbFilePath, g_pConfigManager->m_configCurrentPath);
if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE) if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE)
Debug::log(ERR, "Cannot open input:kb_file= file for reading"); Debug::log(ERR, "Cannot open input:kb_file= file for reading");
else { else {
xkbKeymap = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); m_xkbKeymap = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
fclose(KEYMAPFILE); fclose(KEYMAPFILE);
} }
} }
if (!xkbKeymap) if (!m_xkbKeymap)
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS); m_xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!xkbKeymap) { if (!m_xkbKeymap) {
g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant + g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant +
", options: " + rules.options + ", layout: " + rules.layout + " )"); ", options: " + rules.options + ", layout: " + rules.layout + " )");
@@ -102,38 +102,38 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
rules.options); rules.options);
memset(&XKBRULES, 0, sizeof(XKBRULES)); memset(&XKBRULES, 0, sizeof(XKBRULES));
currentRules.rules = ""; m_currentRules.rules = "";
currentRules.model = ""; m_currentRules.model = "";
currentRules.variant = ""; m_currentRules.variant = "";
currentRules.options = ""; m_currentRules.options = "";
currentRules.layout = "us"; m_currentRules.layout = "us";
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS); m_xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
} }
updateXKBTranslationState(xkbKeymap); updateXKBTranslationState(m_xkbKeymap);
const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default"); const auto NUMLOCKON = g_pConfigManager->getDeviceInt(m_hlName, "numlock_by_default", "input:numlock_by_default");
if (NUMLOCKON == 1) { if (NUMLOCKON == 1) {
// lock numlock // lock numlock
const auto IDX = xkb_map_mod_get_index(xkbKeymap, XKB_MOD_NAME_NUM); const auto IDX = xkb_map_mod_get_index(m_xkbKeymap, XKB_MOD_NAME_NUM);
if (IDX != XKB_MOD_INVALID) if (IDX != XKB_MOD_INVALID)
modifiersState.locked |= (uint32_t)1 << IDX; m_modifiersState.locked |= (uint32_t)1 << IDX;
// 0 to avoid mods getting stuck if depressed during reload // 0 to avoid mods getting stuck if depressed during reload
updateModifiers(0, 0, modifiersState.locked, modifiersState.group); updateModifiers(0, 0, m_modifiersState.locked, m_modifiersState.group);
} }
for (size_t i = 0; i < std::min(LEDNAMES.size(), ledIndexes.size()); ++i) { for (size_t i = 0; i < std::min(LEDNAMES.size(), m_ledIndexes.size()); ++i) {
ledIndexes[i] = xkb_map_led_get_index(xkbKeymap, LEDNAMES[i]); m_ledIndexes[i] = xkb_map_led_get_index(m_xkbKeymap, LEDNAMES[i]);
Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES[i], ledIndexes[i]); Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES[i], m_ledIndexes[i]);
} }
for (size_t i = 0; i < std::min(MODNAMES.size(), modIndexes.size()); ++i) { for (size_t i = 0; i < std::min(MODNAMES.size(), m_modIndexes.size()); ++i) {
modIndexes[i] = xkb_map_mod_get_index(xkbKeymap, MODNAMES[i]); m_modIndexes[i] = xkb_map_mod_get_index(m_xkbKeymap, MODNAMES[i]);
Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES[i], modIndexes[i]); Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES[i], m_modIndexes[i]);
} }
updateKeymapFD(); updateKeymapFD();
@@ -144,59 +144,59 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
} }
void IKeyboard::updateKeymapFD() { void IKeyboard::updateKeymapFD() {
Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName); Debug::log(LOG, "Updating keymap fd for keyboard {}", m_deviceName);
if (xkbKeymapFD.isValid()) if (m_xkbKeymapFD.isValid())
xkbKeymapFD.reset(); m_xkbKeymapFD.reset();
auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); auto cKeymapStr = xkb_keymap_get_as_string(m_xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
xkbKeymapString = cKeymapStr; m_xkbKeymapString = cKeymapStr;
free(cKeymapStr); free(cKeymapStr);
CFileDescriptor rw, ro; CFileDescriptor rw, ro;
if (!allocateSHMFilePair(xkbKeymapString.length() + 1, rw, ro)) if (!allocateSHMFilePair(m_xkbKeymapString.length() + 1, rw, ro))
Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap"); Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap");
else { else {
auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw.get(), 0); auto keymapFDDest = mmap(nullptr, m_xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw.get(), 0);
rw.reset(); rw.reset();
if (keymapFDDest == MAP_FAILED) { if (keymapFDDest == MAP_FAILED) {
Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap"); Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap");
ro.reset(); ro.reset();
} else { } else {
memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length()); memcpy(keymapFDDest, m_xkbKeymapString.c_str(), m_xkbKeymapString.length());
munmap(keymapFDDest, xkbKeymapString.length() + 1); munmap(keymapFDDest, m_xkbKeymapString.length() + 1);
xkbKeymapFD = std::move(ro); m_xkbKeymapFD = std::move(ro);
} }
} }
Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD.get()); Debug::log(LOG, "Updated keymap fd to {}", m_xkbKeymapFD.get());
} }
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (xkbStaticState) if (m_xkbStaticState)
xkb_state_unref(xkbStaticState); xkb_state_unref(m_xkbStaticState);
if (xkbState) if (m_xkbState)
xkb_state_unref(xkbState); xkb_state_unref(m_xkbState);
if (xkbSymState) if (m_xkbSymState)
xkb_state_unref(xkbSymState); xkb_state_unref(m_xkbSymState);
xkbState = nullptr; m_xkbState = nullptr;
xkbStaticState = nullptr; m_xkbStaticState = nullptr;
xkbSymState = nullptr; m_xkbSymState = nullptr;
if (keymap) { if (keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
xkbStaticState = xkb_state_new(keymap); m_xkbStaticState = xkb_state_new(keymap);
xkbState = xkb_state_new(keymap); m_xkbState = xkb_state_new(keymap);
xkbSymState = xkb_state_new(keymap); m_xkbSymState = xkb_state_new(keymap);
return; return;
} }
const auto KEYMAP = xkbKeymap; const auto KEYMAP = m_xkbKeymap;
const auto STATE = xkbState; const auto STATE = m_xkbState;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
@@ -205,9 +205,9 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE) == 1) { if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE) == 1) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an active index {}", (uintptr_t)this, i); Debug::log(LOG, "Updating keyboard {:x}'s translation state from an active index {}", (uintptr_t)this, i);
CVarList keyboardLayouts(currentRules.layout, 0, ','); CVarList keyboardLayouts(m_currentRules.layout, 0, ',');
CVarList keyboardModels(currentRules.model, 0, ','); CVarList keyboardModels(m_currentRules.model, 0, ',');
CVarList keyboardVariants(currentRules.variant, 0, ','); CVarList keyboardVariants(m_currentRules.variant, 0, ',');
xkb_rule_names rules = {.rules = "", .model = "", .layout = "", .variant = "", .options = ""}; xkb_rule_names rules = {.rules = "", .model = "", .layout = "", .variant = "", .options = ""};
@@ -235,9 +235,9 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
} }
xkbState = xkb_state_new(KEYMAP); m_xkbState = xkb_state_new(KEYMAP);
xkbStaticState = xkb_state_new(KEYMAP); m_xkbStaticState = xkb_state_new(KEYMAP);
xkbSymState = xkb_state_new(KEYMAP); m_xkbSymState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP); xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
@@ -249,26 +249,26 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an unknown index", (uintptr_t)this); Debug::log(LOG, "Updating keyboard {:x}'s translation state from an unknown index", (uintptr_t)this);
xkb_rule_names rules = { xkb_rule_names rules = {
.rules = currentRules.rules.c_str(), .rules = m_currentRules.rules.c_str(),
.model = currentRules.model.c_str(), .model = m_currentRules.model.c_str(),
.layout = currentRules.layout.c_str(), .layout = m_currentRules.layout.c_str(),
.variant = currentRules.variant.c_str(), .variant = m_currentRules.variant.c_str(),
.options = currentRules.options.c_str(), .options = m_currentRules.options.c_str(),
}; };
const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkbState = xkb_state_new(NEWKEYMAP); m_xkbState = xkb_state_new(NEWKEYMAP);
xkbStaticState = xkb_state_new(NEWKEYMAP); m_xkbStaticState = xkb_state_new(NEWKEYMAP);
xkbSymState = xkb_state_new(NEWKEYMAP); m_xkbSymState = xkb_state_new(NEWKEYMAP);
xkb_keymap_unref(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
} }
std::string IKeyboard::getActiveLayout() { std::string IKeyboard::getActiveLayout() {
const auto KEYMAP = xkbKeymap; const auto KEYMAP = m_xkbKeymap;
const auto STATE = xkbState; const auto STATE = m_xkbState;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) { for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
@@ -285,12 +285,12 @@ std::string IKeyboard::getActiveLayout() {
} }
std::optional<uint32_t> IKeyboard::getLEDs() { std::optional<uint32_t> IKeyboard::getLEDs() {
if (xkbState == nullptr) if (m_xkbState == nullptr)
return {}; return {};
uint32_t leds = 0; uint32_t leds = 0;
for (uint32_t i = 0; i < std::min((size_t)LED_COUNT, ledIndexes.size()); ++i) { for (uint32_t i = 0; i < std::min((size_t)LED_COUNT, m_ledIndexes.size()); ++i) {
if (xkb_state_led_index_is_active(xkbState, ledIndexes[i])) if (xkb_state_led_index_is_active(m_xkbState, m_ledIndexes[i]))
leds |= (1 << i); leds |= (1 << i);
} }
@@ -307,10 +307,10 @@ void IKeyboard::updateLEDs() {
} }
void IKeyboard::updateLEDs(uint32_t leds) { void IKeyboard::updateLEDs(uint32_t leds) {
if (!xkbState) if (!m_xkbState)
return; return;
if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock())) if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(m_self.lock()))
return; return;
if (!aq()) if (!aq())
@@ -320,13 +320,13 @@ void IKeyboard::updateLEDs(uint32_t leds) {
} }
uint32_t IKeyboard::getModifiers() { uint32_t IKeyboard::getModifiers() {
uint32_t modMask = modifiersState.depressed | modifiersState.latched; uint32_t modMask = m_modifiersState.depressed | m_modifiersState.latched;
uint32_t mods = 0; uint32_t mods = 0;
for (size_t i = 0; i < modIndexes.size(); ++i) { for (size_t i = 0; i < m_modIndexes.size(); ++i) {
if (modIndexes[i] == XKB_MOD_INVALID) if (m_modIndexes[i] == XKB_MOD_INVALID)
continue; continue;
if (!(modMask & (1 << modIndexes[i]))) if (!(modMask & (1 << m_modIndexes[i])))
continue; continue;
mods |= (1 << i); mods |= (1 << i);
@@ -336,50 +336,50 @@ uint32_t IKeyboard::getModifiers() {
} }
void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
if (!xkbState) if (!m_xkbState)
return; return;
xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group); xkb_state_update_mask(m_xkbState, depressed, latched, locked, 0, 0, group);
if (xkbSymState) if (m_xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, group); xkb_state_update_mask(m_xkbSymState, 0, 0, 0, 0, 0, group);
if (!updateModifiersState()) if (!updateModifiersState())
return; return;
keyboardEvents.modifiers.emit(SModifiersEvent{ m_keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed, .depressed = m_modifiersState.depressed,
.latched = modifiersState.latched, .latched = m_modifiersState.latched,
.locked = modifiersState.locked, .locked = m_modifiersState.locked,
.group = modifiersState.group, .group = m_modifiersState.group,
}); });
updateLEDs(); updateLEDs();
} }
bool IKeyboard::updateModifiersState() { bool IKeyboard::updateModifiersState() {
if (!xkbState) if (!m_xkbState)
return false; return false;
auto depressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED); auto depressed = xkb_state_serialize_mods(m_xkbState, XKB_STATE_MODS_DEPRESSED);
auto latched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED); auto latched = xkb_state_serialize_mods(m_xkbState, XKB_STATE_MODS_LATCHED);
auto locked = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED); auto locked = xkb_state_serialize_mods(m_xkbState, XKB_STATE_MODS_LOCKED);
auto group = xkb_state_serialize_layout(xkbState, XKB_STATE_LAYOUT_EFFECTIVE); auto group = xkb_state_serialize_layout(m_xkbState, XKB_STATE_LAYOUT_EFFECTIVE);
if (depressed == modifiersState.depressed && latched == modifiersState.latched && locked == modifiersState.locked && group == modifiersState.group) if (depressed == m_modifiersState.depressed && latched == m_modifiersState.latched && locked == m_modifiersState.locked && group == m_modifiersState.group)
return false; return false;
modifiersState.depressed = depressed; m_modifiersState.depressed = depressed;
modifiersState.latched = latched; m_modifiersState.latched = latched;
modifiersState.locked = locked; m_modifiersState.locked = locked;
modifiersState.group = group; m_modifiersState.group = group;
return true; return true;
} }
void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) { void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
const auto contains = std::find(pressedXKB.begin(), pressedXKB.end(), xkbKey) != pressedXKB.end(); const auto contains = std::find(m_pressedXKB.begin(), m_pressedXKB.end(), xkbKey) != m_pressedXKB.end();
if (contains && pressed) if (contains && pressed)
return; return;
@@ -387,21 +387,21 @@ void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
return; return;
if (contains) if (contains)
std::erase(pressedXKB, xkbKey); std::erase(m_pressedXKB, xkbKey);
else else
pressedXKB.emplace_back(xkbKey); m_pressedXKB.emplace_back(xkbKey);
xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); xkb_state_update_key(m_xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
if (updateModifiersState()) { if (updateModifiersState()) {
if (xkbSymState) if (m_xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, modifiersState.group); xkb_state_update_mask(m_xkbSymState, 0, 0, 0, 0, 0, m_modifiersState.group);
keyboardEvents.modifiers.emit(SModifiersEvent{ m_keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed, .depressed = m_modifiersState.depressed,
.latched = modifiersState.latched, .latched = m_modifiersState.latched,
.locked = modifiersState.locked, .locked = m_modifiersState.locked,
.group = modifiersState.group, .group = m_modifiersState.group,
}); });
} }
} }

View File

@@ -52,7 +52,7 @@ class IKeyboard : public IHID {
CSignal modifiers; CSignal modifiers;
CSignal keymap; CSignal keymap;
CSignal repeatInfo; CSignal repeatInfo;
} keyboardEvents; } m_keyboardEvents;
struct SStringRuleNames { struct SStringRuleNames {
std::string layout = ""; std::string layout = "";
@@ -74,41 +74,46 @@ class IKeyboard : public IHID {
void updateXkbStateWithKey(uint32_t xkbKey, bool pressed); void updateXkbStateWithKey(uint32_t xkbKey, bool pressed);
void updateKeymapFD(); void updateKeymapFD();
bool active = false; bool m_active = false;
bool enabled = true; bool m_enabled = true;
bool m_allowBinds = true;
// if the keymap is overridden by the implementation, // if the keymap is overridden by the implementation,
// don't try to set keyboard rules anymore, to avoid overwriting the requested one. // don't try to set keyboard rules anymore, to avoid overwriting the requested one.
// e.g. Virtual keyboards with custom maps. // e.g. Virtual keyboards with custom maps.
bool keymapOverridden = false; bool m_keymapOverridden = false;
xkb_layout_index_t activeLayout = 0; xkb_layout_index_t m_activeLayout = 0;
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr, xkb_state* m_xkbState = nullptr;
*xkbSymState = nullptr /* Same as static but gets layouts */;
xkb_keymap* xkbKeymap = nullptr; // never gets modifiers or layout changes sent, used for keybinds
xkb_state* m_xkbStaticState = nullptr;
xkb_state* m_xkbSymState = nullptr; // same as static but gets layouts
xkb_keymap* m_xkbKeymap = nullptr;
struct { struct {
uint32_t depressed = 0, latched = 0, locked = 0, group = 0; uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
} modifiersState; } m_modifiersState;
std::array<xkb_led_index_t, 3> ledIndexes = {XKB_MOD_INVALID}; std::array<xkb_led_index_t, 3> m_ledIndexes = {XKB_MOD_INVALID};
std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID}; std::array<xkb_mod_index_t, 8> m_modIndexes = {XKB_MOD_INVALID};
uint32_t leds = 0; uint32_t m_leds = 0;
std::string xkbFilePath = ""; std::string m_xkbFilePath = "";
std::string xkbKeymapString = ""; std::string m_xkbKeymapString = "";
Hyprutils::OS::CFileDescriptor xkbKeymapFD; Hyprutils::OS::CFileDescriptor m_xkbKeymapFD;
SStringRuleNames currentRules; SStringRuleNames m_currentRules;
int repeatRate = 0; int m_repeatRate = 0;
int repeatDelay = 0; int m_repeatDelay = 0;
int numlockOn = -1; int m_numlockOn = -1;
bool resolveBindsBySym = false; bool m_resolveBindsBySym = false;
WP<IKeyboard> self; WP<IKeyboard> m_self;
private: private:
void clearManuallyAllocd(); void clearManuallyAllocd();
std::vector<uint32_t> pressedXKB; std::vector<uint32_t> m_pressedXKB;
}; };

View File

@@ -106,13 +106,13 @@ class IPointer : public IHID {
CSignal holdBegin; CSignal holdBegin;
CSignal holdEnd; CSignal holdEnd;
} pointerEvents; } m_pointerEvents;
bool connected = false; // means connected to the cursor bool m_connected = false; // means connected to the cursor
std::string boundOutput = ""; std::string m_boundOutput = "";
bool flipX = false; // decide to invert horizontal movement bool m_flipX = false; // decide to invert horizontal movement
bool flipY = false; // decide to invert vertical movement bool m_flipY = false; // decide to invert vertical movement
bool isTouchpad = false; bool m_isTouchpad = false;
WP<IPointer> self; WP<IPointer> m_self;
}; };

View File

@@ -42,9 +42,9 @@ class ITouch : public IHID {
CSignal motion; CSignal motion;
CSignal cancel; CSignal cancel;
CSignal frame; CSignal frame;
} touchEvents; } m_touchEvents;
std::string boundOutput = ""; std::string m_boundOutput = "";
WP<ITouch> self; WP<ITouch> m_self;
}; };

View File

@@ -6,7 +6,7 @@
SP<CKeyboard> CKeyboard::create(SP<Aquamarine::IKeyboard> keeb) { SP<CKeyboard> CKeyboard::create(SP<Aquamarine::IKeyboard> keeb) {
SP<CKeyboard> pKeeb = SP<CKeyboard>(new CKeyboard(keeb)); SP<CKeyboard> pKeeb = SP<CKeyboard>(new CKeyboard(keeb));
pKeeb->self = pKeeb; pKeeb->m_self = pKeeb;
return pKeeb; return pKeeb;
} }
@@ -16,22 +16,22 @@ bool CKeyboard::isVirtual() {
} }
SP<Aquamarine::IKeyboard> CKeyboard::aq() { SP<Aquamarine::IKeyboard> CKeyboard::aq() {
return keyboard.lock(); return m_keyboard.lock();
} }
CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : keyboard(keeb) { CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : m_keyboard(keeb) {
if (!keeb) if (!keeb)
return; return;
listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) { m_listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) {
keyboard.reset(); m_keyboard.reset();
events.destroy.emit(); m_events.destroy.emit();
}); });
listeners.key = keeb->events.key.registerListener([this](std::any d) { m_listeners.key = keeb->events.key.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d); auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
keyboardEvents.key.emit(SKeyEvent{ m_keyboardEvents.key.emit(SKeyEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.keycode = E.key, .keycode = E.key,
.state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED, .state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
@@ -40,16 +40,16 @@ CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : keyboard(keeb) {
updateXkbStateWithKey(E.key + 8, E.pressed); updateXkbStateWithKey(E.key + 8, E.pressed);
}); });
listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) { m_listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
updateModifiersState(); updateModifiersState();
keyboardEvents.modifiers.emit(SModifiersEvent{ m_keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed, .depressed = m_modifiersState.depressed,
.latched = modifiersState.latched, .latched = m_modifiersState.latched,
.locked = modifiersState.locked, .locked = m_modifiersState.locked,
.group = modifiersState.group, .group = m_modifiersState.group,
}); });
}); });
deviceName = keeb->getName(); m_deviceName = keeb->getName();
} }

View File

@@ -12,11 +12,11 @@ class CKeyboard : public IKeyboard {
private: private:
CKeyboard(SP<Aquamarine::IKeyboard> keeb); CKeyboard(SP<Aquamarine::IKeyboard> keeb);
WP<Aquamarine::IKeyboard> keyboard; WP<Aquamarine::IKeyboard> m_keyboard;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
CHyprSignalListener key; CHyprSignalListener key;
CHyprSignalListener modifiers; CHyprSignalListener modifiers;
} listeners; } m_listeners;
}; };

View File

@@ -5,51 +5,51 @@
SP<CMouse> CMouse::create(SP<Aquamarine::IPointer> mouse) { SP<CMouse> CMouse::create(SP<Aquamarine::IPointer> mouse) {
SP<CMouse> pMouse = SP<CMouse>(new CMouse(mouse)); SP<CMouse> pMouse = SP<CMouse>(new CMouse(mouse));
pMouse->self = pMouse; pMouse->m_self = pMouse;
return pMouse; return pMouse;
} }
CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) { CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : m_mouse(mouse_) {
if (!mouse) if (!m_mouse)
return; return;
if (auto handle = mouse->getLibinputHandle()) { if (auto handle = m_mouse->getLibinputHandle()) {
double w = 0, h = 0; double w = 0, h = 0;
isTouchpad = libinput_device_has_capability(handle, LIBINPUT_DEVICE_CAP_POINTER) && libinput_device_get_size(handle, &w, &h) == 0; m_isTouchpad = libinput_device_has_capability(handle, LIBINPUT_DEVICE_CAP_POINTER) && libinput_device_get_size(handle, &w, &h) == 0;
} }
listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) { m_listeners.destroy = m_mouse->events.destroy.registerListener([this](std::any d) {
mouse.reset(); m_mouse.reset();
events.destroy.emit(); m_events.destroy.emit();
}); });
listeners.motion = mouse->events.move.registerListener([this](std::any d) { m_listeners.motion = m_mouse->events.move.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SMoveEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SMoveEvent>(d);
pointerEvents.motion.emit(SMotionEvent{ m_pointerEvents.motion.emit(SMotionEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.delta = E.delta, .delta = E.delta,
.unaccel = E.unaccel, .unaccel = E.unaccel,
.mouse = true, .mouse = true,
.device = self.lock(), .device = m_self.lock(),
}); });
}); });
listeners.motionAbsolute = mouse->events.warp.registerListener([this](std::any d) { m_listeners.motionAbsolute = m_mouse->events.warp.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SWarpEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SWarpEvent>(d);
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ m_pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.absolute = E.absolute, .absolute = E.absolute,
.device = self.lock(), .device = m_self.lock(),
}); });
}); });
listeners.button = mouse->events.button.registerListener([this](std::any d) { m_listeners.button = m_mouse->events.button.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SButtonEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SButtonEvent>(d);
pointerEvents.button.emit(SButtonEvent{ m_pointerEvents.button.emit(SButtonEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.button = E.button, .button = E.button,
.state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED, .state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
@@ -57,10 +57,10 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
}); });
}); });
listeners.axis = mouse->events.axis.registerListener([this](std::any d) { m_listeners.axis = m_mouse->events.axis.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SAxisEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SAxisEvent>(d);
pointerEvents.axis.emit(SAxisEvent{ m_pointerEvents.axis.emit(SAxisEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.source = (wl_pointer_axis_source)E.source, .source = (wl_pointer_axis_source)E.source,
.axis = (wl_pointer_axis)E.axis, .axis = (wl_pointer_axis)E.axis,
@@ -71,58 +71,58 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
}); });
}); });
listeners.frame = mouse->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); }); m_listeners.frame = m_mouse->events.frame.registerListener([this](std::any d) { m_pointerEvents.frame.emit(); });
listeners.swipeBegin = mouse->events.swipeBegin.registerListener([this](std::any d) { m_listeners.swipeBegin = m_mouse->events.swipeBegin.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SSwipeBeginEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SSwipeBeginEvent>(d);
pointerEvents.swipeBegin.emit(SSwipeBeginEvent{ m_pointerEvents.swipeBegin.emit(SSwipeBeginEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
}); });
}); });
listeners.swipeEnd = mouse->events.swipeEnd.registerListener([this](std::any d) { m_listeners.swipeEnd = m_mouse->events.swipeEnd.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SSwipeEndEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SSwipeEndEvent>(d);
pointerEvents.swipeEnd.emit(SSwipeEndEvent{ m_pointerEvents.swipeEnd.emit(SSwipeEndEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.cancelled = E.cancelled, .cancelled = E.cancelled,
}); });
}); });
listeners.swipeUpdate = mouse->events.swipeUpdate.registerListener([this](std::any d) { m_listeners.swipeUpdate = m_mouse->events.swipeUpdate.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SSwipeUpdateEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SSwipeUpdateEvent>(d);
pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{ m_pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
.delta = E.delta, .delta = E.delta,
}); });
}); });
listeners.pinchBegin = mouse->events.pinchBegin.registerListener([this](std::any d) { m_listeners.pinchBegin = m_mouse->events.pinchBegin.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SPinchBeginEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SPinchBeginEvent>(d);
pointerEvents.pinchBegin.emit(SPinchBeginEvent{ m_pointerEvents.pinchBegin.emit(SPinchBeginEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
}); });
}); });
listeners.pinchEnd = mouse->events.pinchEnd.registerListener([this](std::any d) { m_listeners.pinchEnd = m_mouse->events.pinchEnd.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SPinchEndEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SPinchEndEvent>(d);
pointerEvents.pinchEnd.emit(SPinchEndEvent{ m_pointerEvents.pinchEnd.emit(SPinchEndEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.cancelled = E.cancelled, .cancelled = E.cancelled,
}); });
}); });
listeners.pinchUpdate = mouse->events.pinchUpdate.registerListener([this](std::any d) { m_listeners.pinchUpdate = m_mouse->events.pinchUpdate.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SPinchUpdateEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SPinchUpdateEvent>(d);
pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{ m_pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
.delta = E.delta, .delta = E.delta,
@@ -131,25 +131,25 @@ CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
}); });
}); });
listeners.holdBegin = mouse->events.holdBegin.registerListener([this](std::any d) { m_listeners.holdBegin = m_mouse->events.holdBegin.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SHoldBeginEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SHoldBeginEvent>(d);
pointerEvents.holdBegin.emit(SHoldBeginEvent{ m_pointerEvents.holdBegin.emit(SHoldBeginEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.fingers = E.fingers, .fingers = E.fingers,
}); });
}); });
listeners.holdEnd = mouse->events.holdEnd.registerListener([this](std::any d) { m_listeners.holdEnd = m_mouse->events.holdEnd.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SHoldEndEvent>(d); auto E = std::any_cast<Aquamarine::IPointer::SHoldEndEvent>(d);
pointerEvents.holdEnd.emit(SHoldEndEvent{ m_pointerEvents.holdEnd.emit(SHoldEndEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.cancelled = E.cancelled, .cancelled = E.cancelled,
}); });
}); });
deviceName = mouse->getName(); m_deviceName = m_mouse->getName();
} }
bool CMouse::isVirtual() { bool CMouse::isVirtual() {
@@ -157,5 +157,5 @@ bool CMouse::isVirtual() {
} }
SP<Aquamarine::IPointer> CMouse::aq() { SP<Aquamarine::IPointer> CMouse::aq() {
return mouse.lock(); return m_mouse.lock();
} }

View File

@@ -12,7 +12,7 @@ class CMouse : public IPointer {
private: private:
CMouse(SP<Aquamarine::IPointer> mouse); CMouse(SP<Aquamarine::IPointer> mouse);
WP<Aquamarine::IPointer> mouse; WP<Aquamarine::IPointer> m_mouse;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
@@ -33,5 +33,5 @@ class CMouse : public IPointer {
CHyprSignalListener holdBegin; CHyprSignalListener holdBegin;
CHyprSignalListener holdEnd; CHyprSignalListener holdEnd;
} listeners; } m_listeners;
}; };

View File

@@ -7,7 +7,7 @@
SP<CTablet> CTablet::create(SP<Aquamarine::ITablet> tablet) { SP<CTablet> CTablet::create(SP<Aquamarine::ITablet> tablet) {
SP<CTablet> pTab = SP<CTablet>(new CTablet(tablet)); SP<CTablet> pTab = SP<CTablet>(new CTablet(tablet));
pTab->self = pTab; pTab->m_self = pTab;
PROTO::tablet->registerDevice(pTab); PROTO::tablet->registerDevice(pTab);
@@ -17,7 +17,7 @@ SP<CTablet> CTablet::create(SP<Aquamarine::ITablet> tablet) {
SP<CTabletTool> CTabletTool::create(SP<Aquamarine::ITabletTool> tablet) { SP<CTabletTool> CTabletTool::create(SP<Aquamarine::ITabletTool> tablet) {
SP<CTabletTool> pTab = SP<CTabletTool>(new CTabletTool(tablet)); SP<CTabletTool> pTab = SP<CTabletTool>(new CTabletTool(tablet));
pTab->self = pTab; pTab->m_self = pTab;
PROTO::tablet->registerDevice(pTab); PROTO::tablet->registerDevice(pTab);
@@ -27,7 +27,7 @@ SP<CTabletTool> CTabletTool::create(SP<Aquamarine::ITabletTool> tablet) {
SP<CTabletPad> CTabletPad::create(SP<Aquamarine::ITabletPad> tablet) { SP<CTabletPad> CTabletPad::create(SP<Aquamarine::ITabletPad> tablet) {
SP<CTabletPad> pTab = SP<CTabletPad>(new CTabletPad(tablet)); SP<CTabletPad> pTab = SP<CTabletPad>(new CTabletPad(tablet));
pTab->self = pTab; pTab->m_self = pTab;
PROTO::tablet->registerDevice(pTab); PROTO::tablet->registerDevice(pTab);
@@ -62,24 +62,24 @@ uint32_t CTablet::getCapabilities() {
} }
SP<Aquamarine::ITablet> CTablet::aq() { SP<Aquamarine::ITablet> CTablet::aq() {
return tablet.lock(); return m_tablet.lock();
} }
CTablet::CTablet(SP<Aquamarine::ITablet> tablet_) : tablet(tablet_) { CTablet::CTablet(SP<Aquamarine::ITablet> tablet_) : m_tablet(tablet_) {
if (!tablet) if (!m_tablet)
return; return;
listeners.destroy = tablet->events.destroy.registerListener([this](std::any d) { m_listeners.destroy = m_tablet->events.destroy.registerListener([this](std::any d) {
tablet.reset(); m_tablet.reset();
events.destroy.emit(); m_events.destroy.emit();
}); });
listeners.axis = tablet->events.axis.registerListener([this](std::any d) { m_listeners.axis = m_tablet->events.axis.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITablet::SAxisEvent>(d); auto E = std::any_cast<Aquamarine::ITablet::SAxisEvent>(d);
tabletEvents.axis.emit(SAxisEvent{ m_tabletEvents.axis.emit(SAxisEvent{
.tool = E.tool, .tool = E.tool,
.tablet = self.lock(), .tablet = m_self.lock(),
.timeMs = E.timeMs, .timeMs = E.timeMs,
.updatedAxes = aqUpdateToHl(E.updatedAxes), .updatedAxes = aqUpdateToHl(E.updatedAxes),
.axis = E.absolute, .axis = E.absolute,
@@ -93,43 +93,43 @@ CTablet::CTablet(SP<Aquamarine::ITablet> tablet_) : tablet(tablet_) {
}); });
}); });
listeners.proximity = tablet->events.proximity.registerListener([this](std::any d) { m_listeners.proximity = m_tablet->events.proximity.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITablet::SProximityEvent>(d); auto E = std::any_cast<Aquamarine::ITablet::SProximityEvent>(d);
tabletEvents.proximity.emit(SProximityEvent{ m_tabletEvents.proximity.emit(SProximityEvent{
.tool = E.tool, .tool = E.tool,
.tablet = self.lock(), .tablet = m_self.lock(),
.timeMs = E.timeMs, .timeMs = E.timeMs,
.proximity = E.absolute, .proximity = E.absolute,
.in = E.in, .in = E.in,
}); });
}); });
listeners.tip = tablet->events.tip.registerListener([this](std::any d) { m_listeners.tip = m_tablet->events.tip.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITablet::STipEvent>(d); auto E = std::any_cast<Aquamarine::ITablet::STipEvent>(d);
tabletEvents.tip.emit(STipEvent{ m_tabletEvents.tip.emit(STipEvent{
.tool = E.tool, .tool = E.tool,
.tablet = self.lock(), .tablet = m_self.lock(),
.timeMs = E.timeMs, .timeMs = E.timeMs,
.tip = E.absolute, .tip = E.absolute,
.in = E.down, .in = E.down,
}); });
}); });
listeners.button = tablet->events.button.registerListener([this](std::any d) { m_listeners.button = m_tablet->events.button.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITablet::SButtonEvent>(d); auto E = std::any_cast<Aquamarine::ITablet::SButtonEvent>(d);
tabletEvents.button.emit(SButtonEvent{ m_tabletEvents.button.emit(SButtonEvent{
.tool = E.tool, .tool = E.tool,
.tablet = self.lock(), .tablet = m_self.lock(),
.timeMs = E.timeMs, .timeMs = E.timeMs,
.button = E.button, .button = E.button,
.down = E.down, .down = E.down,
}); });
}); });
deviceName = tablet->getName(); m_deviceName = m_tablet->getName();
} }
CTablet::~CTablet() { CTablet::~CTablet() {
@@ -145,26 +145,26 @@ uint32_t CTabletPad::getCapabilities() {
} }
SP<Aquamarine::ITabletPad> CTabletPad::aq() { SP<Aquamarine::ITabletPad> CTabletPad::aq() {
return pad.lock(); return m_pad.lock();
} }
eHIDType CTabletPad::getType() { eHIDType CTabletPad::getType() {
return HID_TYPE_TABLET_PAD; return HID_TYPE_TABLET_PAD;
} }
CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) { CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : m_pad(pad_) {
if (!pad) if (!m_pad)
return; return;
listeners.destroy = pad->events.destroy.registerListener([this](std::any d) { m_listeners.destroy = m_pad->events.destroy.registerListener([this](std::any d) {
pad.reset(); m_pad.reset();
events.destroy.emit(); m_events.destroy.emit();
}); });
listeners.button = pad->events.button.registerListener([this](std::any d) { m_listeners.button = m_pad->events.button.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITabletPad::SButtonEvent>(d); auto E = std::any_cast<Aquamarine::ITabletPad::SButtonEvent>(d);
padEvents.button.emit(SButtonEvent{ m_padEvents.button.emit(SButtonEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.button = E.button, .button = E.button,
.down = E.down, .down = E.down,
@@ -173,10 +173,10 @@ CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
}); });
}); });
listeners.ring = pad->events.ring.registerListener([this](std::any d) { m_listeners.ring = m_pad->events.ring.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITabletPad::SRingEvent>(d); auto E = std::any_cast<Aquamarine::ITabletPad::SRingEvent>(d);
padEvents.ring.emit(SRingEvent{ m_padEvents.ring.emit(SRingEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_RING_SOURCE_FINGER, .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_RING_SOURCE_FINGER,
.ring = E.ring, .ring = E.ring,
@@ -185,10 +185,10 @@ CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
}); });
}); });
listeners.strip = pad->events.strip.registerListener([this](std::any d) { m_listeners.strip = m_pad->events.strip.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITabletPad::SStripEvent>(d); auto E = std::any_cast<Aquamarine::ITabletPad::SStripEvent>(d);
padEvents.strip.emit(SStripEvent{ m_padEvents.strip.emit(SStripEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_STRIP_SOURCE_FINGER, .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_STRIP_SOURCE_FINGER,
.strip = E.strip, .strip = E.strip,
@@ -197,11 +197,11 @@ CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
}); });
}); });
listeners.attach = pad->events.attach.registerListener([](std::any d) { m_listeners.attach = m_pad->events.attach.registerListener([](std::any d) {
; // TODO: this doesn't do anything in aq atm ; // TODO: this doesn't do anything in aq atm
}); });
deviceName = pad->getName(); m_deviceName = m_pad->getName();
} }
CTabletPad::~CTabletPad() { CTabletPad::~CTabletPad() {
@@ -213,36 +213,36 @@ uint32_t CTabletTool::getCapabilities() {
} }
SP<Aquamarine::ITabletTool> CTabletTool::aq() { SP<Aquamarine::ITabletTool> CTabletTool::aq() {
return tool.lock(); return m_tool.lock();
} }
eHIDType CTabletTool::getType() { eHIDType CTabletTool::getType() {
return HID_TYPE_TABLET_TOOL; return HID_TYPE_TABLET_TOOL;
} }
CTabletTool::CTabletTool(SP<Aquamarine::ITabletTool> tool_) : tool(tool_) { CTabletTool::CTabletTool(SP<Aquamarine::ITabletTool> tool_) : m_tool(tool_) {
if (!tool) if (!m_tool)
return; return;
listeners.destroyTool = tool->events.destroy.registerListener([this](std::any d) { m_listeners.destroyTool = m_tool->events.destroy.registerListener([this](std::any d) {
tool.reset(); m_tool.reset();
events.destroy.emit(); m_events.destroy.emit();
}); });
if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_TILT) if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_TILT)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT; m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT;
if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_PRESSURE) if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_PRESSURE)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE; m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE;
if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_DISTANCE) if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_DISTANCE)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE; m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE;
if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_ROTATION) if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_ROTATION)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION; m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION;
if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_SLIDER) if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_SLIDER)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER; m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER;
if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_WHEEL) if (m_tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_WHEEL)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL; m_toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL;
deviceName = std::format("{:x}-{:x}", tool->serial, tool->id); m_deviceName = std::format("{:x}-{:x}", m_tool->serial, m_tool->id);
} }
CTabletTool::~CTabletTool() { CTabletTool::~CTabletTool() {
@@ -250,25 +250,25 @@ CTabletTool::~CTabletTool() {
} }
SP<CWLSurfaceResource> CTabletTool::getSurface() { SP<CWLSurfaceResource> CTabletTool::getSurface() {
return pSurface.lock(); return m_surface.lock();
} }
void CTabletTool::setSurface(SP<CWLSurfaceResource> surf) { void CTabletTool::setSurface(SP<CWLSurfaceResource> surf) {
if (surf == pSurface) if (surf == m_surface)
return; return;
if (pSurface) { if (m_surface) {
listeners.destroySurface.reset(); m_listeners.destroySurface.reset();
pSurface.reset(); m_surface.reset();
} }
pSurface = surf; m_surface = surf;
if (surf) { if (surf) {
listeners.destroySurface = surf->events.destroy.registerListener([this](std::any d) { m_listeners.destroySurface = surf->m_events.destroy.registerListener([this](std::any d) {
PROTO::tablet->proximityOut(self.lock()); PROTO::tablet->proximityOut(m_self.lock());
pSurface.reset(); m_surface.reset();
listeners.destroySurface.reset(); m_listeners.destroySurface.reset();
}); });
} }
} }

View File

@@ -86,20 +86,20 @@ class CTablet : public IHID {
CSignal proximity; CSignal proximity;
CSignal tip; CSignal tip;
CSignal button; CSignal button;
} tabletEvents; } m_tabletEvents;
WP<CTablet> self; WP<CTablet> m_self;
bool relativeInput = false; bool m_relativeInput = false;
bool absolutePos = false; bool m_absolutePos = false;
std::string boundOutput = ""; std::string m_boundOutput = "";
CBox activeArea; CBox m_activeArea;
CBox boundBox; CBox m_boundBox;
private: private:
CTablet(SP<Aquamarine::ITablet> tablet); CTablet(SP<Aquamarine::ITablet> tablet);
WP<Aquamarine::ITablet> tablet; WP<Aquamarine::ITablet> m_tablet;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
@@ -107,7 +107,7 @@ class CTablet : public IHID {
CHyprSignalListener proximity; CHyprSignalListener proximity;
CHyprSignalListener tip; CHyprSignalListener tip;
CHyprSignalListener button; CHyprSignalListener button;
} listeners; } m_listeners;
}; };
class CTabletPad : public IHID { class CTabletPad : public IHID {
@@ -148,15 +148,15 @@ class CTabletPad : public IHID {
CSignal ring; CSignal ring;
CSignal strip; CSignal strip;
CSignal attach; CSignal attach;
} padEvents; } m_padEvents;
WP<CTabletPad> self; WP<CTabletPad> m_self;
WP<CTabletTool> parent; WP<CTabletTool> m_parent;
private: private:
CTabletPad(SP<Aquamarine::ITabletPad> pad); CTabletPad(SP<Aquamarine::ITabletPad> pad);
WP<Aquamarine::ITabletPad> pad; WP<Aquamarine::ITabletPad> m_pad;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
@@ -164,7 +164,7 @@ class CTabletPad : public IHID {
CHyprSignalListener strip; CHyprSignalListener strip;
CHyprSignalListener button; CHyprSignalListener button;
CHyprSignalListener attach; CHyprSignalListener attach;
} listeners; } m_listeners;
}; };
class CTabletTool : public IHID { class CTabletTool : public IHID {
@@ -198,23 +198,23 @@ class CTabletTool : public IHID {
SP<CWLSurfaceResource> getSurface(); SP<CWLSurfaceResource> getSurface();
void setSurface(SP<CWLSurfaceResource>); void setSurface(SP<CWLSurfaceResource>);
WP<CTabletTool> self; WP<CTabletTool> m_self;
Vector2D tilt; Vector2D m_tilt;
bool active = false; // true if in proximity bool m_active = false; // true if in proximity
uint32_t toolCapabilities = 0; uint32_t m_toolCapabilities = 0;
bool isDown = false; bool m_isDown = false;
std::vector<uint32_t> buttonsDown; std::vector<uint32_t> m_buttonsDown;
Vector2D absolutePos; // last known absolute position. Vector2D m_absolutePos; // last known absolute position.
private: private:
CTabletTool(SP<Aquamarine::ITabletTool> tool); CTabletTool(SP<Aquamarine::ITabletTool> tool);
WP<CWLSurfaceResource> pSurface; WP<CWLSurfaceResource> m_surface;
WP<Aquamarine::ITabletTool> tool; WP<Aquamarine::ITabletTool> m_tool;
struct { struct {
CHyprSignalListener destroySurface; CHyprSignalListener destroySurface;
CHyprSignalListener destroyTool; CHyprSignalListener destroyTool;
} listeners; } m_listeners;
}; };

View File

@@ -5,62 +5,62 @@
SP<CTouchDevice> CTouchDevice::create(SP<Aquamarine::ITouch> touch) { SP<CTouchDevice> CTouchDevice::create(SP<Aquamarine::ITouch> touch) {
SP<CTouchDevice> pTouch = SP<CTouchDevice>(new CTouchDevice(touch)); SP<CTouchDevice> pTouch = SP<CTouchDevice>(new CTouchDevice(touch));
pTouch->self = pTouch; pTouch->m_self = pTouch;
return pTouch; return pTouch;
} }
CTouchDevice::CTouchDevice(SP<Aquamarine::ITouch> touch_) : touch(touch_) { CTouchDevice::CTouchDevice(SP<Aquamarine::ITouch> touch_) : m_touch(touch_) {
if (!touch) if (!m_touch)
return; return;
listeners.destroy = touch->events.destroy.registerListener([this](std::any d) { m_listeners.destroy = m_touch->events.destroy.registerListener([this](std::any d) {
events.destroy.emit(); m_events.destroy.emit();
touch.reset(); m_touch.reset();
}); });
listeners.down = touch->events.down.registerListener([this](std::any d) { m_listeners.down = m_touch->events.down.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SDownEvent>(d); auto E = std::any_cast<Aquamarine::ITouch::SDownEvent>(d);
touchEvents.down.emit(SDownEvent{ m_touchEvents.down.emit(SDownEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.touchID = E.touchID, .touchID = E.touchID,
.pos = E.pos, .pos = E.pos,
.device = self.lock(), .device = m_self.lock(),
}); });
}); });
listeners.up = touch->events.up.registerListener([this](std::any d) { m_listeners.up = m_touch->events.up.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SUpEvent>(d); auto E = std::any_cast<Aquamarine::ITouch::SUpEvent>(d);
touchEvents.up.emit(SUpEvent{ m_touchEvents.up.emit(SUpEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.touchID = E.touchID, .touchID = E.touchID,
}); });
}); });
listeners.motion = touch->events.move.registerListener([this](std::any d) { m_listeners.motion = m_touch->events.move.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SMotionEvent>(d); auto E = std::any_cast<Aquamarine::ITouch::SMotionEvent>(d);
touchEvents.motion.emit(SMotionEvent{ m_touchEvents.motion.emit(SMotionEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.touchID = E.touchID, .touchID = E.touchID,
.pos = E.pos, .pos = E.pos,
}); });
}); });
listeners.cancel = touch->events.cancel.registerListener([this](std::any d) { m_listeners.cancel = m_touch->events.cancel.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SCancelEvent>(d); auto E = std::any_cast<Aquamarine::ITouch::SCancelEvent>(d);
touchEvents.cancel.emit(SCancelEvent{ m_touchEvents.cancel.emit(SCancelEvent{
.timeMs = E.timeMs, .timeMs = E.timeMs,
.touchID = E.touchID, .touchID = E.touchID,
}); });
}); });
listeners.frame = touch->events.frame.registerListener([this](std::any d) { touchEvents.frame.emit(); }); m_listeners.frame = m_touch->events.frame.registerListener([this](std::any d) { m_touchEvents.frame.emit(); });
deviceName = touch->getName(); m_deviceName = m_touch->getName();
} }
bool CTouchDevice::isVirtual() { bool CTouchDevice::isVirtual() {
@@ -68,5 +68,5 @@ bool CTouchDevice::isVirtual() {
} }
SP<Aquamarine::ITouch> CTouchDevice::aq() { SP<Aquamarine::ITouch> CTouchDevice::aq() {
return touch.lock(); return m_touch.lock();
} }

View File

@@ -12,7 +12,7 @@ class CTouchDevice : public ITouch {
private: private:
CTouchDevice(SP<Aquamarine::ITouch> touch); CTouchDevice(SP<Aquamarine::ITouch> touch);
WP<Aquamarine::ITouch> touch; WP<Aquamarine::ITouch> m_touch;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
@@ -21,5 +21,5 @@ class CTouchDevice : public ITouch {
CHyprSignalListener motion; CHyprSignalListener motion;
CHyprSignalListener cancel; CHyprSignalListener cancel;
CHyprSignalListener frame; CHyprSignalListener frame;
} listeners; } m_listeners;
}; };

View File

@@ -5,43 +5,43 @@
SP<CVirtualKeyboard> CVirtualKeyboard::create(SP<CVirtualKeyboardV1Resource> keeb) { SP<CVirtualKeyboard> CVirtualKeyboard::create(SP<CVirtualKeyboardV1Resource> keeb) {
SP<CVirtualKeyboard> pKeeb = SP<CVirtualKeyboard>(new CVirtualKeyboard(keeb)); SP<CVirtualKeyboard> pKeeb = SP<CVirtualKeyboard>(new CVirtualKeyboard(keeb));
pKeeb->self = pKeeb; pKeeb->m_self = pKeeb;
return pKeeb; return pKeeb;
} }
CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : keyboard(keeb_) { CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : m_keyboard(keeb_) {
if (!keeb_) if (!keeb_)
return; return;
listeners.destroy = keeb_->events.destroy.registerListener([this](std::any d) { m_listeners.destroy = keeb_->m_events.destroy.registerListener([this](std::any d) {
keyboard.reset(); m_keyboard.reset();
events.destroy.emit(); m_events.destroy.emit();
}); });
listeners.key = keeb_->events.key.registerListener([this](std::any d) { keyboardEvents.key.emit(d); }); m_listeners.key = keeb_->m_events.key.registerListener([this](std::any d) { m_keyboardEvents.key.emit(d); });
listeners.modifiers = keeb_->events.modifiers.registerListener([this](std::any d) { m_listeners.modifiers = keeb_->m_events.modifiers.registerListener([this](std::any d) {
auto E = std::any_cast<SModifiersEvent>(d); auto E = std::any_cast<SModifiersEvent>(d);
updateModifiers(E.depressed, E.latched, E.locked, E.group); updateModifiers(E.depressed, E.latched, E.locked, E.group);
keyboardEvents.modifiers.emit(SModifiersEvent{ m_keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed, .depressed = m_modifiersState.depressed,
.latched = modifiersState.latched, .latched = m_modifiersState.latched,
.locked = modifiersState.locked, .locked = m_modifiersState.locked,
.group = modifiersState.group, .group = m_modifiersState.group,
}); });
}); });
listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) { m_listeners.keymap = keeb_->m_events.keymap.registerListener([this](std::any d) {
auto E = std::any_cast<SKeymapEvent>(d); auto E = std::any_cast<SKeymapEvent>(d);
if (xkbKeymap) if (m_xkbKeymap)
xkb_keymap_unref(xkbKeymap); xkb_keymap_unref(m_xkbKeymap);
xkbKeymap = xkb_keymap_ref(E.keymap); m_xkbKeymap = xkb_keymap_ref(E.keymap);
keymapOverridden = true; m_keymapOverridden = true;
updateXKBTranslationState(xkbKeymap); updateXKBTranslationState(m_xkbKeymap);
updateKeymapFD(); updateKeymapFD();
keyboardEvents.keymap.emit(d); m_keyboardEvents.keymap.emit(d);
}); });
deviceName = keeb_->name; m_deviceName = keeb_->m_name;
} }
bool CVirtualKeyboard::isVirtual() { bool CVirtualKeyboard::isVirtual() {
@@ -53,7 +53,7 @@ SP<Aquamarine::IKeyboard> CVirtualKeyboard::aq() {
} }
wl_client* CVirtualKeyboard::getClient() { wl_client* CVirtualKeyboard::getClient() {
if (keyboard.expired()) if (m_keyboard.expired())
return nullptr; return nullptr;
return keyboard->client(); return m_keyboard->client();
} }

View File

@@ -16,12 +16,12 @@ class CVirtualKeyboard : public IKeyboard {
private: private:
CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb); CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb);
WP<CVirtualKeyboardV1Resource> keyboard; WP<CVirtualKeyboardV1Resource> m_keyboard;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
CHyprSignalListener key; CHyprSignalListener key;
CHyprSignalListener modifiers; CHyprSignalListener modifiers;
CHyprSignalListener keymap; CHyprSignalListener keymap;
} listeners; } m_listeners;
}; };

View File

@@ -5,46 +5,46 @@
SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resource) { SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resource) {
SP<CVirtualPointer> pPointer = SP<CVirtualPointer>(new CVirtualPointer(resource)); SP<CVirtualPointer> pPointer = SP<CVirtualPointer>(new CVirtualPointer(resource));
pPointer->self = pPointer; pPointer->m_self = pPointer;
return pPointer; return pPointer;
} }
CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : pointer(resource) { CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : m_pointer(resource) {
if UNLIKELY (!resource->good()) if UNLIKELY (!resource->good())
return; return;
listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) { m_listeners.destroy = m_pointer->m_events.destroy.registerListener([this](std::any d) {
pointer.reset(); m_pointer.reset();
events.destroy.emit(); m_events.destroy.emit();
}); });
listeners.motion = pointer->events.move.registerListener([this](std::any d) { m_listeners.motion = m_pointer->m_events.move.registerListener([this](std::any d) {
auto E = std::any_cast<SMotionEvent>(d); auto E = std::any_cast<SMotionEvent>(d);
E.device = self.lock(); E.device = m_self.lock();
pointerEvents.motion.emit(E); m_pointerEvents.motion.emit(E);
}); });
listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) { m_listeners.motionAbsolute = m_pointer->m_events.warp.registerListener([this](std::any d) {
// we need to unpack the event and add our device here because it's required to calculate the position correctly // we need to unpack the event and add our device here because it's required to calculate the position correctly
auto E = std::any_cast<SMotionAbsoluteEvent>(d); auto E = std::any_cast<SMotionAbsoluteEvent>(d);
E.device = self.lock(); E.device = m_self.lock();
pointerEvents.motionAbsolute.emit(E); m_pointerEvents.motionAbsolute.emit(E);
}); });
listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); }); m_listeners.button = m_pointer->m_events.button.registerListener([this](std::any d) { m_pointerEvents.button.emit(d); });
listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); }); m_listeners.axis = m_pointer->m_events.axis.registerListener([this](std::any d) { m_pointerEvents.axis.emit(d); });
listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); }); m_listeners.frame = m_pointer->m_events.frame.registerListener([this](std::any d) { m_pointerEvents.frame.emit(); });
listeners.swipeBegin = pointer->events.swipeBegin.registerListener([this](std::any d) { pointerEvents.swipeBegin.emit(d); }); m_listeners.swipeBegin = m_pointer->m_events.swipeBegin.registerListener([this](std::any d) { m_pointerEvents.swipeBegin.emit(d); });
listeners.swipeEnd = pointer->events.swipeEnd.registerListener([this](std::any d) { pointerEvents.swipeEnd.emit(d); }); m_listeners.swipeEnd = m_pointer->m_events.swipeEnd.registerListener([this](std::any d) { m_pointerEvents.swipeEnd.emit(d); });
listeners.swipeUpdate = pointer->events.swipeUpdate.registerListener([this](std::any d) { pointerEvents.swipeUpdate.emit(d); }); m_listeners.swipeUpdate = m_pointer->m_events.swipeUpdate.registerListener([this](std::any d) { m_pointerEvents.swipeUpdate.emit(d); });
listeners.pinchBegin = pointer->events.pinchBegin.registerListener([this](std::any d) { pointerEvents.pinchBegin.emit(d); }); m_listeners.pinchBegin = m_pointer->m_events.pinchBegin.registerListener([this](std::any d) { m_pointerEvents.pinchBegin.emit(d); });
listeners.pinchEnd = pointer->events.pinchEnd.registerListener([this](std::any d) { pointerEvents.pinchEnd.emit(d); }); m_listeners.pinchEnd = m_pointer->m_events.pinchEnd.registerListener([this](std::any d) { m_pointerEvents.pinchEnd.emit(d); });
listeners.pinchUpdate = pointer->events.pinchUpdate.registerListener([this](std::any d) { pointerEvents.pinchUpdate.emit(d); }); m_listeners.pinchUpdate = m_pointer->m_events.pinchUpdate.registerListener([this](std::any d) { m_pointerEvents.pinchUpdate.emit(d); });
listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); }); m_listeners.holdBegin = m_pointer->m_events.holdBegin.registerListener([this](std::any d) { m_pointerEvents.holdBegin.emit(d); });
listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); }); m_listeners.holdEnd = m_pointer->m_events.holdEnd.registerListener([this](std::any d) { m_pointerEvents.holdEnd.emit(d); });
boundOutput = resource->boundOutput ? resource->boundOutput->szName : ""; m_boundOutput = resource->m_boundOutput ? resource->m_boundOutput->m_name : "";
deviceName = pointer->name; m_deviceName = m_pointer->m_name;
} }
bool CVirtualPointer::isVirtual() { bool CVirtualPointer::isVirtual() {

View File

@@ -14,7 +14,7 @@ class CVirtualPointer : public IPointer {
private: private:
CVirtualPointer(SP<CVirtualPointerV1Resource>); CVirtualPointer(SP<CVirtualPointerV1Resource>);
WP<CVirtualPointerV1Resource> pointer; WP<CVirtualPointerV1Resource> m_pointer;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;
@@ -35,5 +35,5 @@ class CVirtualPointer : public IPointer {
CHyprSignalListener holdBegin; CHyprSignalListener holdBegin;
CHyprSignalListener holdEnd; CHyprSignalListener holdEnd;
} listeners; } m_listeners;
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,134 @@
#include "AsyncDialogBox.hpp"
#include "./fs/FsUtils.hpp"
#include <csignal>
#include <algorithm>
#include <unistd.h>
#include "../managers/eventLoop/EventLoopManager.hpp"
using namespace Hyprutils::OS;
static std::vector<pid_t> asyncDialogBoxes;
//
SP<CAsyncDialogBox> CAsyncDialogBox::create(const std::string& title, const std::string& description, std::vector<std::string> buttons) {
if (!NFsUtils::executableExistsInPath("hyprland-dialog")) {
Debug::log(ERR, "CAsyncDialogBox: cannot create, no hyprland-dialog");
return nullptr;
}
auto dialog = SP<CAsyncDialogBox>(new CAsyncDialogBox(title, description, buttons));
dialog->m_selfWeakReference = dialog;
return dialog;
}
bool CAsyncDialogBox::isAsyncDialogBox(pid_t pid) {
return std::ranges::contains(asyncDialogBoxes, pid);
}
CAsyncDialogBox::CAsyncDialogBox(const std::string& title, const std::string& description, std::vector<std::string> buttons) :
m_title(title), m_description(description), m_buttons(buttons) {
;
}
static int onFdWrite(int fd, uint32_t mask, void* data) {
auto box = (CAsyncDialogBox*)data;
box->onWrite(fd, mask);
return 0;
}
void CAsyncDialogBox::onWrite(int fd, uint32_t mask) {
if (mask & WL_EVENT_READABLE) {
std::array<char, 1024> buf;
int ret = 0;
// make the FD nonblock for a moment
// TODO: can we avoid this without risking a blocking read()?
int fdFlags = fcntl(fd, F_GETFL, 0);
if (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) {
Debug::log(ERR, "CAsyncDialogBox::onWrite: fcntl 1 failed!");
return;
}
while ((ret = read(m_pipeReadFd.get(), buf.data(), 1023)) > 0) {
m_stdout += std::string_view{(char*)buf.data(), (size_t)ret};
}
// restore the flags (otherwise libwayland wont give us a hangup)
if (fcntl(fd, F_SETFL, fdFlags) < 0) {
Debug::log(ERR, "CAsyncDialogBox::onWrite: fcntl 2 failed!");
return;
}
}
if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
Debug::log(LOG, "CAsyncDialogBox: dialog {:x} hung up, closed.");
m_promiseResolver->resolve(m_stdout);
std::erase(asyncDialogBoxes, m_dialogPid);
wl_event_source_remove(m_readEventSource);
m_selfReference.reset();
return;
}
}
SP<CPromise<std::string>> CAsyncDialogBox::open() {
std::string buttonsString = "";
for (auto& b : m_buttons) {
buttonsString += b + ";";
}
if (!buttonsString.empty())
buttonsString.pop_back();
CProcess proc("hyprland-dialog", std::vector<std::string>{"--title", m_title, "--text", m_description, "--buttons", buttonsString});
int outPipe[2];
if (pipe(outPipe)) {
Debug::log(ERR, "CAsyncDialogBox::open: failed to pipe()");
return nullptr;
}
m_pipeReadFd = CFileDescriptor(outPipe[0]);
proc.setStdoutFD(outPipe[1]);
m_readEventSource = wl_event_loop_add_fd(g_pEventLoopManager->m_wayland.loop, m_pipeReadFd.get(), WL_EVENT_READABLE, ::onFdWrite, this);
if (!m_readEventSource) {
Debug::log(ERR, "CAsyncDialogBox::open: failed to add read fd to loop");
return nullptr;
}
m_selfReference = m_selfWeakReference.lock();
if (!proc.runAsync()) {
Debug::log(ERR, "CAsyncDialogBox::open: failed to run async");
wl_event_source_remove(m_readEventSource);
return nullptr;
}
m_dialogPid = proc.pid();
asyncDialogBoxes.emplace_back(m_dialogPid);
// close the write fd, only the dialog owns it now
close(outPipe[1]);
auto promise = CPromise<std::string>::make([this](SP<CPromiseResolver<std::string>> r) { m_promiseResolver = r; });
return promise;
}
void CAsyncDialogBox::kill() {
if (m_dialogPid <= 0)
return;
::kill(m_dialogPid, SIGKILL);
}
bool CAsyncDialogBox::isRunning() const {
return m_readEventSource;
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include "../macros.hpp"
#include "./memory/Memory.hpp"
#include "./defer/Promise.hpp"
#include <vector>
#include <functional>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/os/FileDescriptor.hpp>
struct wl_event_source;
class CAsyncDialogBox {
public:
static SP<CAsyncDialogBox> create(const std::string& title, const std::string& description, std::vector<std::string> buttons);
static bool isAsyncDialogBox(pid_t pid);
CAsyncDialogBox(const CAsyncDialogBox&) = delete;
CAsyncDialogBox(CAsyncDialogBox&&) = delete;
CAsyncDialogBox& operator=(const CAsyncDialogBox&) = delete;
CAsyncDialogBox& operator=(CAsyncDialogBox&&) = delete;
SP<CPromise<std::string>> open();
void kill();
bool isRunning() const;
void onWrite(int fd, uint32_t mask);
private:
CAsyncDialogBox(const std::string& title, const std::string& description, std::vector<std::string> buttons);
pid_t m_dialogPid = 0;
wl_event_source* m_readEventSource = nullptr;
Hyprutils::OS::CFileDescriptor m_pipeReadFd;
std::string m_stdout = "";
const std::string m_title;
const std::string m_description;
const std::vector<std::string> m_buttons;
SP<CPromiseResolver<std::string>> m_promiseResolver;
// WARNING: cyclic reference. This will be removed once the event source is removed to avoid dangling pointers
SP<CAsyncDialogBox> m_selfReference;
WP<CAsyncDialogBox> m_selfWeakReference;
};

View File

@@ -8,11 +8,11 @@
CHyprColor::CHyprColor() = default; CHyprColor::CHyprColor() = default;
CHyprColor::CHyprColor(float r_, float g_, float b_, float a_) : r(r_), g(g_), b(b_), 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(); m_okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab();
} }
CHyprColor::CHyprColor(uint64_t hex) : r(RED(hex)), g(GREEN(hex)), b(BLUE(hex)), 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(); m_okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab();
} }
CHyprColor::CHyprColor(const Hyprgraphics::CColor& color, float a_) : a(a_) { CHyprColor::CHyprColor(const Hyprgraphics::CColor& color, float a_) : a(a_) {
@@ -21,7 +21,7 @@ CHyprColor::CHyprColor(const Hyprgraphics::CColor& color, float a_) : a(a_) {
g = SRGB.g; g = SRGB.g;
b = SRGB.b; b = SRGB.b;
okLab = color.asOkLab(); m_okLab = color.asOkLab();
} }
uint32_t CHyprColor::getAsHex() const { uint32_t CHyprColor::getAsHex() const {
@@ -33,11 +33,11 @@ Hyprgraphics::CColor::SSRGB CHyprColor::asRGB() const {
} }
Hyprgraphics::CColor::SOkLab CHyprColor::asOkLab() const { Hyprgraphics::CColor::SOkLab CHyprColor::asOkLab() const {
return okLab; return m_okLab;
} }
Hyprgraphics::CColor::SHSL CHyprColor::asHSL() const { Hyprgraphics::CColor::SHSL CHyprColor::asHSL() const {
return Hyprgraphics::CColor(okLab).asHSL(); return Hyprgraphics::CColor(m_okLab).asHSL();
} }
CHyprColor CHyprColor::stripA() const { CHyprColor CHyprColor::stripA() const {

View File

@@ -43,7 +43,7 @@ class CHyprColor {
double r = 0, g = 0, b = 0, a = 0; double r = 0, g = 0, b = 0, a = 0;
private: private:
Hyprgraphics::CColor::SOkLab okLab; // cache for the OkLab representation Hyprgraphics::CColor::SOkLab m_okLab; // cache for the OkLab representation
}; };
//NOLINTNEXTLINE //NOLINTNEXTLINE

View File

@@ -1,43 +1,43 @@
#include "DamageRing.hpp" #include "DamageRing.hpp"
void CDamageRing::setSize(const Vector2D& size_) { void CDamageRing::setSize(const Vector2D& size_) {
if (size_ == size) if (size_ == m_size)
return; return;
size = size_; m_size = size_;
damageEntire(); damageEntire();
} }
bool CDamageRing::damage(const CRegion& rg) { bool CDamageRing::damage(const CRegion& rg) {
CRegion clipped = rg.copy().intersect(CBox{{}, size}); CRegion clipped = rg.copy().intersect(CBox{{}, m_size});
if (clipped.empty()) if (clipped.empty())
return false; return false;
current.add(clipped); m_current.add(clipped);
return true; return true;
} }
void CDamageRing::damageEntire() { void CDamageRing::damageEntire() {
damage(CBox{{}, size}); damage(CBox{{}, m_size});
} }
void CDamageRing::rotate() { void CDamageRing::rotate() {
previousIdx = (previousIdx + DAMAGE_RING_PREVIOUS_LEN - 1) % DAMAGE_RING_PREVIOUS_LEN; m_previousIdx = (m_previousIdx + DAMAGE_RING_PREVIOUS_LEN - 1) % DAMAGE_RING_PREVIOUS_LEN;
previous[previousIdx] = current; m_previous[m_previousIdx] = m_current;
current.clear(); m_current.clear();
} }
CRegion CDamageRing::getBufferDamage(int age) { CRegion CDamageRing::getBufferDamage(int age) {
if (age <= 0 || age > DAMAGE_RING_PREVIOUS_LEN + 1) if (age <= 0 || age > DAMAGE_RING_PREVIOUS_LEN + 1)
return CBox{{}, size}; return CBox{{}, m_size};
CRegion damage = current; CRegion damage = m_current;
for (int i = 0; i < age - 1; ++i) { for (int i = 0; i < age - 1; ++i) {
int j = (previousIdx + i) % DAMAGE_RING_PREVIOUS_LEN; int j = (m_previousIdx + i) % DAMAGE_RING_PREVIOUS_LEN;
damage.add(previous.at(j)); damage.add(m_previous.at(j));
} }
// don't return a ludicrous amount of rects // don't return a ludicrous amount of rects
@@ -48,5 +48,5 @@ CRegion CDamageRing::getBufferDamage(int age) {
} }
bool CDamageRing::hasChanged() { bool CDamageRing::hasChanged() {
return !current.empty(); return !m_current.empty();
} }

View File

@@ -15,8 +15,8 @@ class CDamageRing {
bool hasChanged(); bool hasChanged();
private: private:
Vector2D size; Vector2D m_size;
CRegion current; CRegion m_current;
std::array<CRegion, DAMAGE_RING_PREVIOUS_LEN> previous; std::array<CRegion, DAMAGE_RING_PREVIOUS_LEN> m_previous;
size_t previousIdx = 0; size_t m_previousIdx = 0;
}; };

View File

@@ -122,7 +122,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
const auto NAME = in.substr(8); const auto NAME = in.substr(8);
const auto WS = g_pCompositor->getWorkspaceByName("special:" + NAME); const auto WS = g_pCompositor->getWorkspaceByName("special:" + NAME);
return {WS ? WS->m_iID : g_pCompositor->getNewSpecialID(), "special:" + NAME}; return {WS ? WS->m_id : g_pCompositor->getNewSpecialID(), "special:" + NAME};
} }
result.id = SPECIAL_WORKSPACE_START; result.id = SPECIAL_WORKSPACE_START;
@@ -133,13 +133,13 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
if (!WORKSPACE) { if (!WORKSPACE) {
result.id = g_pCompositor->getNextAvailableNamedWorkspace(); result.id = g_pCompositor->getNextAvailableNamedWorkspace();
} else { } else {
result.id = WORKSPACE->m_iID; result.id = WORKSPACE->m_id;
} }
result.name = WORKSPACENAME; result.name = WORKSPACENAME;
} else if (in.starts_with("empty")) { } else if (in.starts_with("empty")) {
const bool same_mon = in.substr(5).contains("m"); const bool same_mon = in.substr(5).contains("m");
const bool next = in.substr(5).contains("n"); const bool next = in.substr(5).contains("n");
if ((same_mon || next) && !g_pCompositor->m_pLastMonitor) { if ((same_mon || next) && !g_pCompositor->m_lastMonitor) {
Debug::log(ERR, "Empty monitor workspace on monitor null!"); Debug::log(ERR, "Empty monitor workspace on monitor null!");
return {WORKSPACE_INVALID}; return {WORKSPACE_INVALID};
} }
@@ -148,12 +148,12 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
if (same_mon) { if (same_mon) {
for (auto const& rule : g_pConfigManager->getAllWorkspaceRules()) { for (auto const& rule : g_pConfigManager->getAllWorkspaceRules()) {
const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor);
if (PMONITOR && (PMONITOR->ID != g_pCompositor->m_pLastMonitor->ID)) if (PMONITOR && (PMONITOR->m_id != g_pCompositor->m_lastMonitor->m_id))
invalidWSes.insert(rule.workspaceId); invalidWSes.insert(rule.workspaceId);
} }
} }
WORKSPACEID id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; WORKSPACEID id = next ? g_pCompositor->m_lastMonitor->activeWorkspaceID() : 0;
while (++id < LONG_MAX) { while (++id < LONG_MAX) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!invalidWSes.contains(id) && (!PWORKSPACE || PWORKSPACE->getWindows() == 0)) { if (!invalidWSes.contains(id) && (!PWORKSPACE || PWORKSPACE->getWindows() == 0)) {
@@ -162,24 +162,47 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
} }
} }
} else if (in.starts_with("prev")) { } else if (in.starts_with("prev")) {
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_lastMonitor)
return {WORKSPACE_INVALID}; return {WORKSPACE_INVALID};
const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; const auto PWORKSPACE = g_pCompositor->m_lastMonitor->m_activeWorkspace;
if (!valid(PWORKSPACE)) if (!valid(PWORKSPACE))
return {WORKSPACE_INVALID}; return {WORKSPACE_INVALID};
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->getPrevWorkspaceIDName().id); const auto PREVWORKSPACEIDNAME = PWORKSPACE->getPrevWorkspaceIDName();
if (!PLASTWORKSPACE) if (PREVWORKSPACEIDNAME.id == -1)
return {WORKSPACE_INVALID}; return {WORKSPACE_INVALID};
return {PLASTWORKSPACE->m_iID, PLASTWORKSPACE->m_szName}; const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PREVWORKSPACEIDNAME.id);
if (!PLASTWORKSPACE) {
Debug::log(LOG, "previous workspace {} doesn't exist yet", PREVWORKSPACEIDNAME.id);
return {PREVWORKSPACEIDNAME.id, PREVWORKSPACEIDNAME.name};
}
return {PLASTWORKSPACE->m_id, PLASTWORKSPACE->m_name};
} else if (in == "next") {
if (!g_pCompositor->m_lastMonitor || !g_pCompositor->m_lastMonitor->m_activeWorkspace) {
Debug::log(ERR, "no active monitor or workspace for 'next'");
return {WORKSPACE_INVALID};
}
auto PCURRENTWORKSPACE = g_pCompositor->m_lastMonitor->m_activeWorkspace;
WORKSPACEID nextId = PCURRENTWORKSPACE->m_id + 1;
if (nextId <= 0)
return {WORKSPACE_INVALID};
result.id = nextId;
result.name = std::to_string(nextId);
return result;
} else { } else {
if (in[0] == 'r' && (in[1] == '-' || in[1] == '+' || in[1] == '~') && isNumber(in.substr(2))) { if (in[0] == 'r' && (in[1] == '-' || in[1] == '+' || in[1] == '~') && isNumber(in.substr(2))) {
bool absolute = in[1] == '~'; bool absolute = in[1] == '~';
if (!g_pCompositor->m_pLastMonitor) { if (!g_pCompositor->m_lastMonitor) {
Debug::log(ERR, "Relative monitor workspace on monitor null!"); Debug::log(ERR, "Relative monitor workspace on monitor null!");
return {WORKSPACE_INVALID}; return {WORKSPACE_INVALID};
} }
@@ -196,15 +219,15 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
std::set<WORKSPACEID> invalidWSes; std::set<WORKSPACEID> invalidWSes;
// Collect all the workspaces we can't jump to. // Collect all the workspaces we can't jump to.
for (auto const& ws : g_pCompositor->m_vWorkspaces) { for (auto const& ws : g_pCompositor->m_workspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor)) { if (ws->m_isSpecialWorkspace || (ws->m_monitor != g_pCompositor->m_lastMonitor)) {
// Can't jump to this workspace // Can't jump to this workspace
invalidWSes.insert(ws->m_iID); invalidWSes.insert(ws->m_id);
} }
} }
for (auto const& rule : g_pConfigManager->getAllWorkspaceRules()) { for (auto const& rule : g_pConfigManager->getAllWorkspaceRules()) {
const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor);
if (!PMONITOR || PMONITOR->ID == g_pCompositor->m_pLastMonitor->ID) { if (!PMONITOR || PMONITOR->m_id == g_pCompositor->m_lastMonitor->m_id) {
// Can't be invalid // Can't be invalid
continue; continue;
} }
@@ -214,11 +237,11 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
// Prepare all named workspaces in case when we need them // Prepare all named workspaces in case when we need them
std::vector<WORKSPACEID> namedWSes; std::vector<WORKSPACEID> namedWSes;
for (auto const& ws : g_pCompositor->m_vWorkspaces) { for (auto const& ws : g_pCompositor->m_workspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor) || ws->m_iID >= 0) if (ws->m_isSpecialWorkspace || (ws->m_monitor != g_pCompositor->m_lastMonitor) || ws->m_id >= 0)
continue; continue;
namedWSes.push_back(ws->m_iID); namedWSes.push_back(ws->m_id);
} }
std::sort(namedWSes.begin(), namedWSes.end()); std::sort(namedWSes.begin(), namedWSes.end());
@@ -242,7 +265,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
} else { } else {
// Just take a blind guess at where we'll probably end up // Just take a blind guess at where we'll probably end up
WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; WORKSPACEID activeWSID = g_pCompositor->m_lastMonitor->m_activeWorkspace ? g_pCompositor->m_lastMonitor->m_activeWorkspace->m_id : 1;
WORKSPACEID predictedWSID = activeWSID + remains; WORKSPACEID predictedWSID = activeWSID + remains;
int remainingWSes = 0; int remainingWSes = 0;
char walkDir = in[1]; char walkDir = in[1];
@@ -333,7 +356,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(result.id); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(result.id);
if (PWORKSPACE) if (PWORKSPACE)
result.name = g_pCompositor->getWorkspaceByID(result.id)->m_szName; result.name = g_pCompositor->getWorkspaceByID(result.id)->m_name;
else else
result.name = std::to_string(result.id); result.name = std::to_string(result.id);
@@ -341,7 +364,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
bool onAllMonitors = in[0] == 'e'; bool onAllMonitors = in[0] == 'e';
bool absolute = in[1] == '~'; bool absolute = in[1] == '~';
if (!g_pCompositor->m_pLastMonitor) { if (!g_pCompositor->m_lastMonitor) {
Debug::log(ERR, "Relative monitor workspace on monitor null!"); Debug::log(ERR, "Relative monitor workspace on monitor null!");
return {WORKSPACE_INVALID}; return {WORKSPACE_INVALID};
} }
@@ -358,11 +381,11 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
int remains = (int)result.id; int remains = (int)result.id;
std::vector<WORKSPACEID> validWSes; std::vector<WORKSPACEID> validWSes;
for (auto const& ws : g_pCompositor->m_vWorkspaces) { for (auto const& ws : g_pCompositor->m_workspaces) {
if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor && !onAllMonitors)) if (ws->m_isSpecialWorkspace || (ws->m_monitor != g_pCompositor->m_lastMonitor && !onAllMonitors))
continue; continue;
validWSes.push_back(ws->m_iID); validWSes.push_back(ws->m_id);
} }
std::sort(validWSes.begin(), validWSes.end()); std::sort(validWSes.begin(), validWSes.end());
@@ -384,7 +407,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size(); remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size();
// get the current item // get the current item
WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; WORKSPACEID activeWSID = g_pCompositor->m_lastMonitor->m_activeWorkspace ? g_pCompositor->m_lastMonitor->m_activeWorkspace->m_id : 1;
for (ssize_t i = 0; i < (ssize_t)validWSes.size(); i++) { for (ssize_t i = 0; i < (ssize_t)validWSes.size(); i++) {
if (validWSes[i] == activeWSID) { if (validWSes[i] == activeWSID) {
currentItem = i; currentItem = i;
@@ -404,11 +427,11 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
} }
result.id = validWSes[currentItem]; result.id = validWSes[currentItem];
result.name = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName; result.name = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_name;
} else { } else {
if (in[0] == '+' || in[0] == '-') { if (in[0] == '+' || in[0] == '-') {
if (g_pCompositor->m_pLastMonitor) { if (g_pCompositor->m_lastMonitor) {
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspaceID()); const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, g_pCompositor->m_lastMonitor->activeWorkspaceID());
if (!PLUSMINUSRESULT.has_value()) if (!PLUSMINUSRESULT.has_value())
return {WORKSPACE_INVALID}; return {WORKSPACE_INVALID};
@@ -423,7 +446,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) {
// maybe name // maybe name
const auto PWORKSPACE = g_pCompositor->getWorkspaceByName(in); const auto PWORKSPACE = g_pCompositor->getWorkspaceByName(in);
if (PWORKSPACE) if (PWORKSPACE)
result.id = PWORKSPACE->m_iID; result.id = PWORKSPACE->m_id;
} }
result.name = std::to_string(result.id); result.name = std::to_string(result.id);
@@ -817,3 +840,38 @@ float stringToPercentage(const std::string& VALUE, const float REL) {
else else
return std::stof(VALUE); return std::stof(VALUE);
} }
// Checks if Nvidia driver major version is at least given version.
// Useful for explicit_sync_kms and ctm_animation as they only work
// past certain driver versions.
bool isNvidiaDriverVersionAtLeast(int threshold) {
static int driverMajor = 0;
static bool once = true;
if (once) {
once = false;
std::error_code ec;
if (std::filesystem::exists("/sys/module/nvidia_drm/version", ec) && !ec) {
std::ifstream ifs("/sys/module/nvidia_drm/version");
if (ifs.good()) {
try {
std::string driverInfo((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
size_t firstDot = driverInfo.find('.');
if (firstDot != std::string::npos)
driverMajor = std::stoi(driverInfo.substr(0, firstDot));
Debug::log(LOG, "Parsed NVIDIA major version: {}", driverMajor);
} catch (std::exception& e) {
driverMajor = 0; // Default to 0 if parsing fails
}
ifs.close();
}
}
}
return driverMajor >= threshold;
}

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