Compare commits

...

275 Commits

Author SHA1 Message Date
Vaxry
9a09eac79b props: bump version to 0.42.0 2024-08-07 21:17:10 +02:00
Vaxry
2d552fbaa2 renderer: fixup nvidia driver version checks 2024-08-07 18:54:45 +02:00
Vaxry
ea72831541 wayland/compositor: introduce client commit events 2024-08-07 17:04:49 +02:00
Tom Englund
a399f98c68 cursormgr: avoid scanning ill formed inherit (#7211)
avoid adding ill formed Inherit lines to inherit vector and later
scanning them, it wont change anything in practice but makes the inherit
theme parsing more in line with what its supposed todo. also check for
return values of the various string functions so we dont end up erasing
the wrong thing.
2024-08-07 16:37:09 +02:00
Agent00Ming
3e00d7dde7 compositor: fix general:extend_border_grab_area (#7214)
Co-authored-by: Agent_00Ming <agent00ming9366@gmail.com>
2024-08-07 16:36:20 +02:00
Sami Liedes
d5bc3eb1fa hyprctl: link to much less libraries (#7212)
This makes hyprctl start significantly faster.

$ time for ((i=0; i<1000; i++)); do hyprctl/hyprctl -j activewindow >/dev/null; done

Before: 12.269 s (about 12.3 ms/execution)
After: 2.142 s (about 2.1 ms/execution)
2024-08-07 16:28:02 +02:00
Vaxry
99e9cb5107 drm-syncobj: fixup fd leak with timelines 2024-08-07 16:08:50 +02:00
Vaxry
f36c625e37 compositor: minor cleanups for fading out layers 2024-08-07 13:35:02 +02:00
Vaxry
2e3dc17a7e renderer: guard layer in renderLayer
ref #7181
2024-08-07 13:31:32 +02:00
outfoxxed
b2717cf7fd xdg-shell: make xdg-positioner flip target greatest available space (#7209)
When both flip directions use more space than is available, pick the
direction that has more space available instead of just the opposite
of what was initially requested.
2024-08-07 13:26:09 +02:00
Tom Englund
3d82d199f0 cursormgr: implement inheriting themes for xcursor (#7197)
* cursormgr: reduce duplicated code

add a few functions such as setCursorBuffer and setAnimationTimer to
reduce duplicated code and also avoid future mishaps of forgetting to
clear buffer or disarm timer. and generally reduce spaghetti even tho
pasta can be delicious.

* xcursormgr: implent inherited themes

implent index.theme parsing and inherited themes.

* cursormgr: ensure a fallback xcursor exist

ensure a xcursor fallback exist otherwise it wont load the proper theme
if we at launch have hyprcursor enabled and then set it to false in
config and reload. also use the env var when using hyprctl setcursor
incase its empty.
2024-08-07 13:23:00 +02:00
Ikalco
a05da63d85 keybinds: fix NoSymbol keybinds (#7199) 2024-08-07 13:22:19 +02:00
Tom Englund
5b736a4a66 debug: dont manually unlock the lock_guard (#7210)
when lock_guard goes out of scope it RAII itself and calls unlock.
causes crashes on freebsd/libc++ and double unlocking a mutex is UB.
2024-08-07 13:22:01 +02:00
Ikalco
fa6ee51367 input: fix leds on kb creation (#7206) 2024-08-07 08:44:20 +01:00
Vaxry
b0a70f63e3 wayland/compositor: drop pending buffer ref if synchronous
fixes https://github.com/hyprwm/hyprpicker/issues/85
2024-08-06 17:08:22 +02:00
Vaxry
d597ae41b9 renderer: fixup crashes on inaccessible files for bg 2024-08-06 16:57:15 +02:00
Vaxry
640d161851 renderer: Explicit sync fixes (#7151)
Enables explicit sync by default for most platforms

`misc:no_direct_scanout` -> `render:direct_scanout`
2024-08-06 15:52:19 +02:00
Tom Englund
0e86808e59 cursor: Better xcursor implementation (#7178)
* xcursor: bootleg xcursors into its own manager

implent XCursorManager and load themes based on librarypath and its
dir, now we catch all supplied theme files. and also implent animated
cursors. also refactor a bit of spaghetti regarding xcursors in
CursorManager.

* hyprcursor: fix buffer leak

animated cursors are creating a new buffer for each image, ensure we
drop the buffers so it continously doesnt build up in infinity.

* cursormgr: use eventloopmgr for animation

use EvenloopManager for timers instead of adding it directly to
m_sWLEventLoop and using its related wl_* functions.
2024-08-05 19:58:21 +02:00
MightyPlaza
2b520571e8 keybinds: improve fullscreenstate toggling (#7174)
modified:   src/managers/KeybindManager.cpp
2024-08-04 21:40:34 +02:00
Mihai Fufezan
5dd2c27b63 CMake, Meson: install config and wallpapers to DATADIR/hypr
OpenGL: get wallpapers dir from DATAROOTDIR
2024-08-04 15:19:37 +03:00
MaroonSkull
4ae89e1f22 CMake: Suppress CMake warning about GNUInstallDirs 2024-08-04 12:10:50 +03:00
MightyPlaza
51ffd7fa6f decorations: fix infinite recursion on no_gaps when only (#7169)
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp
modified:   src/render/decorations/CHyprBorderDecoration.cpp
2024-08-03 19:50:08 +02:00
Vaxry
ae50f8614d wayland/surface: fixup self-owning surface roles
fixes #7133
2024-08-03 17:58:06 +02:00
Jan Beich
9f5a57ff45 core: Add missing header for libc++ after e989a0bcff (#7158)
src/Compositor.cpp:2295:74: error: no member named 'bit_floor' in namespace 'std'
 2295 |     const eFullscreenMode CURRENT_EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)PWINDOW->m_sFullscreenState.internal);
      |                                                                     ~~~~~^
src/Compositor.cpp:2296:74: error: no member named 'bit_floor' in namespace 'std'
 2296 |     const eFullscreenMode EFFECTIVE_MODE         = (eFullscreenMode)std::bit_floor((uint8_t)state.internal);
      |                                                                     ~~~~~^
src/desktop/Window.cpp:1242:34: error: no member named 'bit_floor' in namespace 'std'
 1242 |     return (eFullscreenMode)std::bit_floor((uint8_t)m_sFullscreenState.internal) == MODE;
      |                             ~~~~~^
2024-08-03 13:02:10 +01:00
Tom Englund
4141e67550 xcursor: rework bootleg xcursor (#7140)
there were a bunch of missing cursors, rework the shape loading add a
function to get legacyname from new wayland names. also bootleg add a
cursor if no theme can be found and no shape. to atleast show
something.
2024-08-02 23:16:20 +02:00
Tuur Vanhoutte
be2dfa36ef hyprctl: increase hyprctl timeout to 5s to fix #6801 (#7152) 2024-08-02 21:49:47 +02:00
Vaxry
1fa4b7d79b hyprerror: minor stylistic changes 2024-08-02 18:42:10 +02:00
Maximilian Seidler
592b4a709c sessionLock: don't sendLocked when session lock has already been destoyed (#7150)
* sessionLock: reset m_pSessionLock on destroy

* sessionLock: only send locked when resource is good
2024-08-02 15:25:51 +02:00
Vaxry
09bb5658b7 window/ls: reset core signals after destroy
fixes #7137
2024-08-02 00:31:44 +02:00
Vaxry
ab0a3268e0 xdg-shell: fixup unassigned wl surfaces to xdg surfaces
fixes #7133
2024-08-01 15:43:19 +02:00
MightyPlaza
c8873b958d internal: fix fullscreen typos (#7134)
modified:   src/events/Windows.cpp
modified:   src/layout/DwindleLayout.cpp
2024-08-01 14:59:52 +02:00
Vaxry
60571cd5cc border: fixup infinite recursion
ref #7127
2024-08-01 12:36:15 +02:00
Vaxry
5edfa627b4 layershell: don't throw misaligned error on exclusive edge 0
ref #7108
2024-08-01 11:46:04 +02:00
MightyPlaza
95959789b7 keybinds: allow toggling fullscreenstate (#7128)
modified:   src/managers/KeybindManager.cpp
2024-08-01 11:43:32 +02:00
Sungyoon Cho
8c02b3c267 layout: fix dynamic rules not updating after setting fullscreen (#7129) 2024-08-01 11:43:02 +02:00
Tom Englund
5b7057c479 pointer: fix buffer crash (#7131)
current buffer->buffer can turn out to be null actually check for its
existence or use the lastbuffer when calling updateCursorShm()
2024-08-01 11:42:22 +02:00
Vaxry
37e1411e8d core/surface/buffer: Buffer lock/release fixes (#7110) 2024-07-31 21:47:26 +02:00
Tom Englund
5489682799 internal: some minor fd/socket cleanups and make logging thread safe (#7123)
* bezier: dont loop on float values

Using a floating-point loop variable with a fixed increment can cause precision
errors over time due to the nature of floating-point arithmetic.
and cause undesired effects.

ex
iteration 1 = 0.10000000149011611938
iteration 2 = 0.20000000298023223877

eventually..

iteration 8 = 0.80000001192092895508
iteration 9 = 0.89999997615814208984

* hyprctl: close sockets on destruction

store socketpath and close the fd and unlink the socket path on exit.

* eventloopmgr: close the timerfd

close the timerfd on exit.

* debug: make logging thread safe

instead of opening and closing the logfile on each write open it on init
and close it on compositor exit. also add a mutex so accidently using
logging from a thread like the watchdog or similiar doesnt cause issues.

* xwl: clean up fd logic

check if the fd is actually opened before closing, and close the
pipesource FD on exit.
2024-07-31 21:00:14 +02:00
MightyPlaza
e989a0bcff internal: refactor fullscreen states (#7104)
* refactor fullscreen
modified:   src/Compositor.cpp
modified:   src/Compositor.hpp
modified:   src/config/ConfigManager.cpp
modified:   src/config/ConfigManager.hpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/LayerSurface.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/desktop/Workspace.cpp
modified:   src/desktop/Workspace.hpp
modified:   src/events/Windows.cpp
modified:   src/helpers/Monitor.cpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/DwindleLayout.hpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/layout/IHyprLayout.hpp
modified:   src/layout/MasterLayout.cpp
modified:   src/layout/MasterLayout.hpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/KeybindManager.hpp
modified:   src/managers/input/IdleInhibitor.cpp
modified:   src/managers/input/InputManager.cpp
modified:   src/managers/input/Swipe.cpp
modified:   src/protocols/ForeignToplevelWlr.cpp
modified:   src/render/Renderer.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* clean up
modified:   src/config/ConfigManager.cpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.hpp
modified:   src/desktop/Workspace.cpp
modified:   src/events/Windows.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/input/Swipe.cpp

* fix mapWindow fullscreen
modified:   src/events/Windows.cpp

* fix typo
modified:   src/desktop/Workspace.cpp

* add fullscreenstate
modified:   src/config/ConfigManager.cpp
modified:   src/events/Windows.cpp

* change syncFullscreen to lower
modified:   src/config/ConfigManager.hpp

* initialize fs state
modified:   src/desktop/Window.hpp
2024-07-31 19:55:52 +02:00
André Silva
8a5f9bbb39 keybinds: handle null monitor in pinActive (#7122) 2024-07-31 17:54:07 +02:00
Ikalco
3b9b5346b8 protocols: Move globalshortcuts impl (#7102)
* move global shortcuts to hyprwayland-scanner

* remove wayland-scanner from deps

* fix the thing
2024-07-30 23:33:56 +02:00
Mihai Fufezan
8ec3dc4c09 CI: update actions
flake.lock: update aquamarine and xdph
2024-07-30 22:13:48 +03:00
Vaxry
cc7c117fe7 output: minor tearing fixes 2024-07-30 15:50:14 +02:00
Vaxry
1c221240d0 output: submit damage to kms 2024-07-30 15:46:41 +02:00
vaxerski
c1afc82a4c [gha] Nix: update inputs 2024-07-30 13:34:22 +00:00
Vaxry
f3a9f9ec45 pointer: use preMonitorCommit for resetting render state
in DS preRender is not called
2024-07-30 15:32:42 +02:00
jim3692
10e631053a compositor: fix log typos (#7111) 2024-07-30 13:50:13 +02:00
Vaxry
46c6efeab3 hyprpm: execute all git commands regardless of fails 2024-07-30 12:11:38 +02:00
Vaxry
68ee4dda5e hyprpm: warn about uncheckoutable commits 2024-07-30 12:05:23 +02:00
Vaxry
743e98f0c0 hyprpm: add short error code explanations 2024-07-30 11:54:28 +02:00
Vaxry
e673220340 core/surface: fixup a few pointer handling edge cases 2024-07-29 19:29:08 +02:00
Tom Englund
9c38b0fdbe core: add a destructor to CHyprOpenglImpl and avoid wl_container_of undefined behaviour (#7101)
* protocols: avoid undefined behaviour in C macro

to safely use wl_container_of with a class the class has to be no
virtual functions, no inheritance, and uniform access control (e.g all
public)

work around this by putting this into a destroywrapper struct.

* opengl: clean memory on destruction

add a destructor and free the allocated memory and close the fd
2024-07-29 19:29:08 +02:00
Ikalco
60b663e276 protocols: move text-input-v1 to hyprwayland-scanner (#7096)
* move text-input-v1 to hyprwayland-scanner

* vro
2024-07-29 18:14:19 +02:00
Vaxry
01560c9d7c virtualptr: map to entire screen if no output is provided
fixes #6749
2024-07-29 18:13:23 +02:00
atikiNBTW
3a1afb53fd pluginapi: Add force reload of config at the end of plugin initialization (#7099)
* Add force reload of config at the end of plugin load

* Remove unnecessary include
2024-07-29 16:56:50 +02:00
Vaxry
23a8f06594 virtualptr: allow binding to output 2024-07-29 16:27:09 +02:00
Vaxry
70468857da egl: attempt a 3.2 egl context first 2024-07-29 14:27:05 +02:00
Vaxry
87699575e1 egl: require gles 3.0 only
No clue what could break, hopefully nothing

ref #6973
2024-07-29 14:23:19 +02:00
outfoxxed
33e513d489 xdg-shell: fix xdg-positioner y-flip (#7094) 2024-07-29 09:48:27 +01:00
Virt
6e6c61b9e8 layer-shell: avoid crashes on unmap (#7092) 2024-07-29 09:47:25 +01:00
vaxerski
a9d87bd666 surface: emit unmap before unmapping and releasing the buffers 2024-07-28 23:56:35 +02:00
vaxerski
7df9b01d48 core: emit unmap event after unmap in surface destroy 2024-07-28 23:47:17 +02:00
vaxerski
256db08aed layersurface: null check for surface validity before unmap() 2024-07-28 23:41:41 +02:00
vaxerski
73d09953e8 core/surface: drop map/unmap events in member funcs
causes loops
2024-07-28 23:41:41 +02:00
Mihai Fufezan
fcff2dcac2 flake.lock: update xdph 2024-07-28 18:42:05 +03:00
Mihai Fufezan
3cc2028def hyprpm: checkout commit instead of branch
Fixes #6948
2024-07-28 14:03:46 +03:00
Sungyoon Cho
9b6ae4f77b input: fix keyboard leds with multiple keyboards (#7079) 2024-07-28 11:46:38 +01:00
outfoxxed
bc86afea7e xdg-shell: completely rewrite xdg-positioner (#7067)
This implementation actually works.
2024-07-27 21:43:01 +01:00
vaxerski
6edfdd63a1 surface: avoid crashes on fading out layers 2024-07-27 22:15:36 +02:00
Mihai Fufezan
04b40ea2ec CI: only run once for PRs with branches from original repo (#7075) 2024-07-27 22:17:05 +03:00
Mihai Fufezan
55ceca4cdd flake.lock: update aquamarine 2024-07-27 20:32:11 +03:00
Mihai Fufezan
10e8af00d6 flake.lock: update hyprutils 2024-07-27 19:51:43 +03:00
MightyPlaza
ad711ef421 input: unify removing currentlyDraggedWindow (#7071)
modified:   src/desktop/Window.cpp
modified:   src/events/Windows.cpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/KeybindManager.hpp
modified:   src/managers/input/InputManager.cpp
2024-07-27 17:46:19 +01:00
vaxerski
ae638d997d configmgr: fix warning 2024-07-27 18:15:47 +02:00
vaxerski
141cd09bd3 renderer: use session lock alpha for rendering lacking locks 2024-07-27 18:13:41 +02:00
vaxerski
0243271544 layer-shell: properly map and unmap surface and propagate unmap events 2024-07-27 18:08:22 +02:00
vaxerski
729b47d46d input: refocus last window on keyboard unfocusable surfaces
fixes #4460
2024-07-27 17:49:35 +02:00
MahouShoujoMivutilde
84227eb587 input: Fix hyprctl switchxkblayout not actually changing layout (#7070)
Emits `SModifiersEvent` in `updateModifiers()`

Before the patch:

Changing layout with `hyprctl switchxkblayout ...` results in:
    * active keymap in `hyprctl devices` is changed
    * no event
    * no layout is actually changed UNTIL you press one of the mod keys
      (Alt | Shift | Super | Ctrl)

After:
    * active keymap in `hyprctl devices` changed
    * activelayout IPC event emitted
    * layout is changed

This fixes https://github.com/hyprwm/Hyprland/issues/7044
2024-07-27 16:43:45 +01:00
vaxerski
daed75219f wayland/compositor: fixup double buffer releases
fixes #7043
2024-07-27 17:04:03 +02:00
Ikalco
ec672b1ab9 protocols: move screencopy and toplevel export to hyprwayland-scanner (#7065)
* move screencopy and toplevel export to hyprwayland-scanner

* oops
2024-07-27 16:02:02 +01:00
vaxerski
963816b9a6 layersurface: fixup focus issues in onUnmap
fixes #6929
2024-07-27 15:04:03 +02:00
Mihai Fufezan
534fdb5a37 flake.lock: update 2024-07-27 15:57:52 +03:00
vaxerski
682865632f xwayland: fix high cpu idle usage
fixes #7051
2024-07-27 13:58:30 +02:00
vaxerski
76610d9fb0 opengl: destroy cairo image surface after use 2024-07-27 13:03:43 +02:00
vaxerski
57371b93a0 renderer: drastically optimize bg texture creation
stop loading 20MB images every time, dumbass
2024-07-26 19:53:24 +02:00
Vaxry
33a5c8ce32 config: avoid using initial ws tracking for exec-once 2024-07-25 15:29:39 +02:00
Vaxry
a0d15a0b7b wayland/compositor: release buffers on unmap
XWayland does not use the regular commit(null) method to unmap, which results in buffers never being released.

release the buffers if present and un-released in the unmap() handler

ref #6584
2024-07-25 14:12:08 +02:00
Vaxry
cd942ad12d keyboard: update xkb state after key event
fixes #6946
2024-07-25 13:10:53 +02:00
Vaxry
daf5fad190 keyboard: properly update keymap state and fd on keymap changes
needed for virtual keyboards that impose their own layouts.

fixes #6991
2024-07-25 13:02:10 +02:00
MightyPlaza
4beac91cbd keybinds: add safeguard to mousebinds (#7034)
modified:   src/managers/KeybindManager.cpp
2024-07-25 00:19:15 +02:00
Anton Lazarev
391f1ae838 input: don't simulate mouse movement on focus change in follow_mouse = 2/3 if no_warps is false (#7015) 2024-07-25 00:16:47 +02:00
Mihai Fufezan
381cb2d833 flake.lock: update aquamarine 2024-07-24 23:51:23 +03:00
MightyPlaza
a0be3de0e8 keybinds: handle monitor change in moveWindowIntoGroup (#7030)
modified:   src/managers/KeybindManager.cpp
2024-07-24 20:00:25 +02:00
Ikalco
3e543d2ce8 core: Properly shutdown wl display (#7018)
* correctly destroy wayland globals

* properly shutdown and cleanup hyprland

* appease the nitpick gods and some comments
2024-07-24 19:07:36 +02:00
MightyPlaza
735e3c6c56 crashreporter: add date and flags to crash report (#7028)
modified:   src/debug/CrashReporter.cpp
2024-07-24 19:05:54 +02:00
Vaxry
b16fb9770c egl: support getting the device via platform_device
a neat EXT
2024-07-24 18:53:51 +02:00
MightyPlaza
f2b6ebbf54 keybinds: remove toggleopaque (#7024)
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/KeybindManager.hpp
2024-07-24 18:53:51 +02:00
Vaxry
fe19754887 shortcutsInhibit: fix crash 2024-07-24 16:26:44 +02:00
MightyPlaza
72bce7efd5 keybinds: add bindp and noshortcutsinhibit (#7017) 2024-07-24 14:10:36 +02:00
Vaxry
99088eaed8 compositor: simplify getWindowFromSurface 2024-07-24 11:07:28 +02:00
Leon
2da3cfb422 touch: fix touch swipe invert config (#7014) 2024-07-24 10:59:50 +02:00
Leon
e2efecc24e flake: update aquamarine 2024-07-24 01:42:15 +03:00
Vaxry
8a4548e430 window: drop ack requirement for applying pending reported size
fixes #6533
2024-07-23 23:38:58 +02:00
Ikalco
a5f58a3126 layer-shell: validate exclusiveEdge and don't set it as top by default (#7006)
* validate exclusiveEdge and don't set it as top by default

* make sure exclusive edge anchor is within bounds
2024-07-23 20:03:15 +02:00
Vaxry
077494ee85 surface: fix zero_scaling xwayland damage 2024-07-23 19:56:47 +02:00
Mihai Fufezan
752604cfe9 Nix: remove meson (used by wlroots) 2024-07-23 20:40:33 +03:00
Sam Lakerveld
3c758db95c renderer/layer-shell: use explicitly set exclusiveEdge (#6984) 2024-07-22 23:36:58 +02:00
Vaxry
7c68236a51 egl: avoid setting debug mode and handle legacyrenderer
ref #6973
2024-07-22 23:05:22 +02:00
Vaxry
4c3b035162 pointer/hw: rollback the swapchain on multiple renders without a commit
fixes the hack
2024-07-22 19:19:37 +02:00
Vaxry
f17f8b219c pointer/hw: extend cursor swapchain to 3
otherwise on some commits we draw twice and we draw over the front buffer
2024-07-22 19:05:45 +02:00
Ikalco
e8374e0792 debug: get rid of useless 1s in logs (#6969)
* get rid of 1s in logs lol

* replace WLR with AQ in logs
2024-07-22 18:06:11 +02:00
Vaxry
77b134e23b virtual-pointer: fixup virtual pointer warp events
fixes #6976
2024-07-22 17:24:30 +02:00
Vaxry
87db950189 wl_seat: avoid sending events to objects without caps
ref #6835
2024-07-22 16:57:35 +02:00
Vaxry
5bae7f150b wayland/output: avoid sending events to dead outputs
ref #6835
2024-07-22 16:56:51 +02:00
diniamo
83a5395eaa flake: update xdph 2024-07-22 14:47:06 +03:00
diniamo
d03fa94c2c core: avoid locking 2 wayland sockets (#6971)
* fix: avoid locking 2 wayland sockets

* format

* fix formatting
2024-07-22 13:16:25 +02:00
UjinT34
511e9ccdd1 xwm: Fix xwayland black window bug after losing focus (#6966)
* fix xwayland black window bug

* resend normal state
2024-07-22 13:15:40 +02:00
Vaxry
3132f0275e touch: set lastInputTouch on every event 2024-07-22 13:05:06 +02:00
Vaxry
1797319a07 renderer: untransform textures matching display transform
fixes #6754

This will break if the client uses a transform that is not equal to the display, reverting to old behavior. Combining transforms is left as a todo for the future.
2024-07-22 13:01:55 +02:00
Vaxry
5979ceb56b surface: fixup logical damage size calculations
fixes #6618
2024-07-22 12:38:05 +02:00
Vaxry
672bf1f867 compositor: ignore setting surface scanout if DS is disabled 2024-07-21 23:52:16 +02:00
Vaxry
33e933e2a0 renderer: drop redundant spammy trace log 2024-07-21 22:09:29 +02:00
Vaxry
341fb4497f wayland/compositor: fixup buffer damage tracking for wl_shm buffers
remove qt hack, fixup conditions

fixes #6844
2024-07-21 22:05:53 +02:00
Vaxry
cbaac6deaf xwm: drop invalid case for clearing X focus
fixes #6955
2024-07-21 20:02:48 +02:00
Vaxry
3b6bcd6ddc presentation-feedback: fix invalid values sent after aq merge 2024-07-21 19:25:07 +02:00
Mihai Fufezan
e6fc9873b5 flake.lock: update 2024-07-21 19:31:36 +03:00
Mihai Fufezan
db1f5cd137 CMake: fmt 2024-07-21 19:25:42 +03:00
Mihai Fufezan
928d1dd38a CMake, Meson, Nix: replace props.json with VERSION 2024-07-21 19:24:17 +03:00
Mihai Fufezan
faa157e162 gitignore: add CMake residual files 2024-07-21 19:24:17 +03:00
Vaxry
7f624d2236 xwayland: fixup WM_SIZE_HINTS handling according to ICCCM 2024-07-21 17:41:26 +02:00
Vaxry
f7fb7e7e49 xwayland: avoid unfocusing on OR child focuses
fixes #6698
2024-07-21 17:27:36 +02:00
Vaxry
efcbcd7297 input: fix invalid usage of dev in setTouchDeviceConfigs
ref #6943
2024-07-21 16:45:46 +02:00
Vaxry
043b859ea2 hyprpm: init submodules after resets
ref #6948
2024-07-21 16:42:49 +02:00
khachbe
cf373d315e touch: add touch swipe invert config (#6940) 2024-07-21 13:59:09 +02:00
Vaxry
016da234d0 Core: Move to aquamarine (#6608)
Moves Hyprland from wlroots to aquamarine for the backend.

---------

Signed-off-by: Vaxry <vaxry@vaxry.net>
Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
Co-authored-by: Jan Beich <jbeich@FreeBSD.org>
Co-authored-by: vaxerski <vaxerski@users.noreply.github.com>
Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com>
Co-authored-by: Tom Englund <tomenglund26@gmail.com>
Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com>
Co-authored-by: diniamo <diniamo53@gmail.com>
2024-07-21 13:09:54 +02:00
phonetic112
f642fb97df core: Fix crash on opening chromium (#6932) 2024-07-20 10:11:32 +02:00
vaxerski
9b0993cc49 [gha] build man pages 2024-07-19 22:37:42 +00:00
Ferdinand Bachmann
efccf25fcc compositor: implement wayland socket handover (#6930)
* compositor: implement wayland socket handover

This commit implements the compositor side of the Wayland socket
handover protocol as described in the [KDE Wiki]. The CLI options are
chosen so that they are compatible with Kwin.

[KDE Wiki]: https://invent.kde.org/plasma/kwin/-/wikis/Restarting

* main: verify that --wayland-fd is a valid file descriptor

* main: fail if only one of --socket and --wayland-fd is passed
2024-07-20 00:37:20 +02:00
Agent00Ming
8e15f91c24 input: Emulate discrete scrolling from v120 events (#6881)
* seat: avoid sending axis_stop() when source is wheel

 * fix rounding for absolute discrete values greater than 1

Co-authored-by: Agent_00Ming <agent00ming9366@gmail.com>
2024-07-18 21:57:08 +02:00
VESSE Léo
300228b503 flake: add clang-tools to devShell (#6916) 2024-07-17 23:30:02 +03:00
Party Wumpus
293e687389 renderer: Make shader time always count from zero (#6903)
* testing out an initialtime variable

* Make time universally start at zero instead of exposing an initial time

* Appease the CI
2024-07-16 22:03:10 +02:00
Mihai Fufezan
da956c8a97 config: use hyprutils helper (#6891)
* flake.lock: update

nix/overlays: remove xwayland overlay (merged upstream)

* config: use hyprutils helper

* flake.lock: update

* CMake & Meson: update required versions
2024-07-16 21:23:37 +02:00
Khiet Tam Nguyen
bd526822de config: add option to exit window while retaining fullscreen (#516) (#6880)
* feat: saving fullscreen mode and state for restoring later

* style: no p-prefix, capitalised constants
2024-07-15 13:48:04 +02:00
MightyPlaza
f442f435d3 layout: update workspace rules on layout change (#6878)
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/layout/MasterLayout.cpp
2024-07-15 11:57:52 +02:00
Khiet Tam Nguyen
bc6b0880dd window: override noMaximize if new window takes over fullscreen (#6812) (#6870) 2024-07-13 20:44:32 +02:00
MightyPlaza
ed6c701144 renderer: partially revert previous xray fix (#6868)
modified:   src/render/OpenGL.cpp
2024-07-13 20:29:07 +02:00
Tim Waterhouse
45c4898423 socket2: Add windowtitlev2 event which includes the window address (#6856)
Fixes #5393
2024-07-13 16:21:32 +02:00
David De Sousa
a770a88e09 toplevelexport: fix flipped r/b channels when sharing windows (#6861)
fixes #6823
2024-07-13 12:53:53 +02:00
Tim Waterhouse
1f64668953 ext-foreign-toplevel: Send done after title and class (#6857)
According to the spec (https://wayland.app/protocols/ext-foreign-toplevel-list-v1#ext_foreign_toplevel_handle_v1:event:title), clients should wait for the done signal before applying updates
2024-07-13 12:53:23 +02:00
Vaxry
13bc7e1e14 style: fix clang-format 2024-07-13 12:36:35 +02:00
Junxuan Liao
7486576fa7 session-lock: send locked after the lock screen is properly rendered (#6850)
The protocol says:
> The locked event "must not be sent until a new "locked" frame (either from a
> session lock surface or the compositor blanking the output) has been presented
> on all outputs and no security sensitive normal/unlocked content is possibly
> visible".

This helps users ensure the screen is properly locked before suspending
the machine. (e.g. with swaylock --ready-fd)
2024-07-13 12:32:08 +02:00
MightyPlaza
f85c6416c6 renderer: fix a few xray regressions (#6855)
* fix xray unset
modified:   src/render/OpenGL.cpp

* fix xwray unset
modified:   src/render/OpenGL.cpp
2024-07-12 23:05:19 +02:00
Virt
e728e56cbc meson: install wayland.hpp header 2024-07-11 23:58:23 +03:00
Maximilian Seidler
9ff83f4aa9 sessionLock: fix the check for locking a locked session (#6843) 2024-07-11 16:40:43 +02:00
vaxerski
3247d18a7c [gha] Nix: update inputs 2024-07-11 14:12:19 +00:00
MightyPlaza
a443902abc core: Improve handling of window properties (#6776)
* add mWindowProperties

modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/events/Windows.cpp

* support int values
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp

* create m_sWindowData

modified:   src/Compositor.cpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/events/Windows.cpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/layout/MasterLayout.cpp
modified:   src/managers/AnimationManager.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/XWaylandManager.cpp
modified:   src/render/OpenGL.cpp
modified:   src/render/Renderer.cpp
modified:   src/render/decorations/CHyprBorderDecoration.cpp
modified:   src/render/decorations/CHyprDropShadowDecoration.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* simplify some properties
modified:   src/Compositor.cpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/managers/KeybindManager.cpp

* store multiple values in CWindowOverridableVar
modified:   src/Compositor.cpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/events/Windows.cpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/managers/AnimationManager.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/XWaylandManager.cpp
modified:   src/render/OpenGL.cpp
modified:   src/render/Renderer.cpp
modified:   src/render/decorations/CHyprBorderDecoration.cpp
modified:   src/render/decorations/CHyprDropShadowDecoration.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* clean up
modified:   src/Compositor.cpp
modified:   src/Compositor.hpp
modified:   src/config/ConfigManager.cpp
modified:   src/config/ConfigManager.hpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/events/Windows.cpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/layout/IHyprLayout.hpp
modified:   src/layout/MasterLayout.cpp
modified:   src/managers/KeybindManager.cpp

* use SET_PROP priority for exec rules
modified:   src/config/ConfigManager.hpp
modified:   src/desktop/Window.cpp

* add default value
modified:   src/Compositor.cpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/events/Windows.cpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/XWaylandManager.cpp
modified:   src/render/OpenGL.cpp
modified:   src/render/Renderer.cpp
modified:   src/render/decorations/CHyprBorderDecoration.cpp
modified:   src/render/decorations/CHyprDropShadowDecoration.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp

* add setprop toggle
modified:   src/config/ConfigManager.hpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp

* add setprop toggle
modified:   src/debug/HyprCtl.cpp

* make window rules functional
modified:   src/config/ConfigManager.cpp
modified:   src/desktop/Window.cpp

* minor fixes
modified:   src/Compositor.cpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.hpp

* properly clean layout data
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/events/Windows.cpp
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/layout/IHyprLayout.hpp
modified:   src/layout/MasterLayout.cpp

* remove newline
modified:   src/events/Windows.cpp

* fixes
modified:   src/config/ConfigManager.hpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp

* use CamelCase
modified:   src/Compositor.cpp
modified:   src/debug/HyprCtl.cpp
modified:   src/desktop/Window.cpp
modified:   src/desktop/Window.hpp
modified:   src/events/Windows.cpp
modified:   src/layout/IHyprLayout.cpp
modified:   src/managers/AnimationManager.cpp
modified:   src/managers/KeybindManager.cpp
modified:   src/managers/XWaylandManager.cpp
modified:   src/render/OpenGL.cpp
modified:   src/render/Renderer.cpp
modified:   src/render/decorations/CHyprBorderDecoration.cpp
modified:   src/render/decorations/CHyprDropShadowDecoration.cpp
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
2024-07-11 16:10:42 +02:00
Ikalco
b03f41efec xwayland: fix setting title prop (#6809)
* fix setting xwayland title prop

* add window title types
2024-07-08 17:46:42 +02:00
André Silva
648f824b9e flake.lock: update 2024-07-08 18:24:54 +03:00
Virt
22138ac259 workspaces: don't try to reopen special workspaces (#6802) 2024-07-07 21:27:18 +02:00
Yusuf
19fb13e6cf internal: Add functions to hyprctl header (#6745)
* add functions to hyprctl header

* refactor monitor json into own function and add it to header

* format hyprctl.hpp

* move functions to namespace

* move helper functions to class
2024-07-07 17:52:56 +02:00
Maximilian Seidler
ede1e63f69 config: don't crash when getenv HOME returns null 2024-07-07 16:59:03 +03:00
Vaxry
cc98594c3a pointer: update geometry after unplug events
fixes #6700

fixes #6740
2024-07-05 23:05:09 +02:00
MightyPlaza
0502c3f62b keybinds: fix movewindow float to 0 (#6777)
modified:   src/managers/KeybindManager.cpp
2024-07-05 22:46:38 +02:00
Lincoln Yuji de Oliveira
0a6e83005f Completions: use only awk (#6763) 2024-07-04 14:21:07 +03:00
Agent00Ming
e894d5e964 tablet: Send .frame() on .proximity_out() (#6761)
Co-authored-by: Agent_00Ming <agent00ming9366@gmail.com>
2024-07-03 21:40:18 +02:00
Lincoln Yuji
8bb75a223d hyprctl completions: Use only awk rather than grep + awk
Using "awk '/<exp>/{ print $n }'" is more minimal and slightly faster
than using "grep '<exp>' | awk '{ print $n }'".

Signed-off-by: Lincoln Yuji <lincolnyuji@hotmail.com>
2024-07-02 22:46:20 +03:00
Vaxry
6247a6b537 renderer: don't skip back background on preBlurQueued
fixes #6332
2024-07-02 18:40:27 +02:00
drendog
2fa57f2dc4 pointer: change min cursor padding to 0 (#6027)
* fix: change min cursor padding to 0

* chore: set default hotspot padding to 0

* fix: adjusting clamp after getting closest point to fix getting off limit point

* fix: deal with floating point to clamp to prev value

* refactor: max coords to vector

* fix: remove box closestPoint adjustment due its fix on hyprutils
2024-07-02 12:17:48 +02:00
Ikalco
e58fd3bfb0 meson: fix wlroots-hyprland dep checks (for libliftoff patch to work) (#6736) 2024-07-02 12:14:27 +02:00
Tom Englund
d7ea1b7785 xwayland: break cyclic loop of parents (#6722)
in X11 some surfaces is a parent of itself and creates a cyclic loop
when trying to find its parent. check for old parent and break if its
beginning to roll over.
2024-07-01 00:26:08 +02:00
UjinT34
4d6f96f74f debug: add Nvidia driver info (#6715)
* add nvidia driver info to systeminfo

* check file exists
2024-06-30 13:16:41 +02:00
Tom Englund
8ff9410d2c inputmgr: ensure we dont divide by zero (#6713)
some weird combination of scrolling/nesting hyprland and closing a
window i managed to divide by zero here, reported by ubsan. add a check
to ensure we dont hit UB.
2024-06-30 13:15:59 +02:00
はれなよ
718afe271e seat: don't send keyboard data without a keyboard cap (#6697)
* Fix #6279: prevent sending keymap or repeat info events by keyboards without keyboard capability

* Remove brackets
2024-06-29 20:05:07 +02:00
はれなよ
1f43a5c859 session: fix activate events being always treated as on (#6696)
* Fix listener_sessionActive to handle an event correctly when the session get inactivated

* Remove log
2024-06-29 20:04:48 +02:00
Vaxry
9c5dd59d4b input: fix capabilities enum types passed
hyprland down to the seat protocol impl expects IHID capabilities, not WL_ ones

ref #6702 #6196
2024-06-29 00:23:02 +02:00
Vaxry
d16c6aa1db pointer-constraint: set lifetime correctly
ref #6679
2024-06-29 00:18:24 +02:00
Tom Englund
ac11771348 core: fix a few ubsan issues reported at exit of hyprland (#6699)
* watchdog: dont detach and cause race condition

instead of detaching and causing a race condition on destruction where
the thread is alive and watchdog has been destroyed, check if its
joinable and join it on destruction.

causes heap use after free on exit of compositor.

* render: add checks for compositor shutting down

avoid member call on null pointer, if the g_pHyprRenderer is destroyed
we can call the member makeEGLCurrent on it, causes undefined behaviour
on destruction of the compositor/hyprrenderer.

found with ubsan.
2024-06-28 22:24:32 +02:00
Alexander
f2dc48d92f keybinds: never switch to another monitor with per_monitor (#6665)
Co-authored-by: Крылов Александр <aleksandr.krylov@hyperus.team>
2024-06-27 15:07:56 +02:00
outfoxxed
e4d09aa3a9 sessionLock: focus lock on creation based on mouse position (#6658)
* sessionLock: focus lock on creation based on mouse position

* sessionLock: immediately unfocus any focused surfaces on lock
2024-06-25 23:22:38 +02:00
Vaxry
c338acbb7d ime-relay: fix crash on nullptr surface focus 2024-06-25 22:46:36 +02:00
Vaxry
95782de966 renderer: don't use the surface counter in popup iterations
fixes #6663
2024-06-25 20:04:02 +02:00
Vaxry
3ba3d20ad3 pointer: round position when rendering software cursors
otherwise the image gets resampled and gets blurry
2024-06-25 18:44:54 +02:00
Vaxry
1d70962892 core: move to steady_clock where applicable
avoid issues when system clock gets desynchronized or changed
2024-06-25 16:05:47 +02:00
Mihai Fufezan
918d8340af flake.lock: update 2024-06-25 15:06:02 +03:00
Vaxry
4f7113972e props: bump version to 0.41.2 2024-06-25 13:53:41 +02:00
Vaxry
8121e66f34 cmake: bump hyprutils dep to 0.1.5 2024-06-25 13:50:59 +02:00
Gregory
784c0b5ccb keybinds: fix mouse pass (#6652)
* keybinds: fix mouse pass

* keybinds: keep mouse and keyboard focus separate after pass bind
2024-06-25 13:46:49 +02:00
outfoxxed
eef207ce0a output: fix cursors disappearing after dpms (#6659) 2024-06-25 12:55:54 +02:00
Vaxry
4dd2b5902e hyprctl: add a newline after log() 2024-06-24 23:58:10 +02:00
Vaxry
cff0123ce6 wl-compositor: don't send enter to defunct output globals 2024-06-24 23:29:26 +02:00
Vaxry
8a68199a0c foreign-toplevel-wlr: fix out-of-range for missing monitor resources
fixes #6635
2024-06-23 19:49:53 +02:00
Mihai Fufezan
e09addf8de Workspace.hpp: fix include 2024-06-23 16:43:53 +03:00
John Titor
315f16d501 dbus: import PATH XDG_DATA_DIRS variables into systemd and dbus session 2024-06-23 16:11:50 +03:00
Alexander
7f09646ab8 core: add ability to select previous workspace per monitor (#6598)
Co-authored-by: Крылов Александр <aleksandr.krylov@hyperus.team>
2024-06-22 23:52:42 +02:00
MariuszTrybus
0b924f541c constraints: Lock surface region when region is empty (#6627)
* Pointer constraints: Lock surface region when region is empty

* Format code
2024-06-22 17:05:05 +02:00
Ikalco
4778afe2e6 hyprctl: make recv timeout bigger and give error message if it does timeout (#6621) 2024-06-22 00:41:23 +02:00
Tom Englund
fa022901cf surface: add virtual destructor to surfacerole to avoid undefined behaviour (#6620)
* surfacerole: add virtual destructor

all classes that will be derived from should have a virtual destructor
otherwise deleting an instance via pointer to a base class is undefined
behaviour, layershell/xdgshell hits this with std::default_delete in the
new sharedptr implentation.

* includes: fix missing includes

fix missing includes for no precompiled headers builds, and remove a
redefiniton of a macro already defined in macros.hpp
2024-06-22 00:40:45 +02:00
Vaxry
4a8b13ea4f renderer: shrink occlusion rect if blur is used
if we are blurring, we cannot be sure whether the occluded region won't be included in the expanded damage. If it is, we'd get dark shimmers.

fixes #6547
2024-06-21 19:25:34 +02:00
Vaxry
8cf2ca1966 math: include cstring for memset
fixup name too
2024-06-21 19:20:15 +02:00
Vaxry
fabc30df52 format: include macros for unreachable 2024-06-20 00:15:24 +02:00
Przegryw321
d6de248b0d window: expose pseudotiled state and add param to dispatcher (#6583)
* Show pseudotiled state of window in hyprctl clients

* Add a window as an optional argument for the pseudo dispatcher

* change formatting
2024-06-19 23:19:18 +02:00
Vaxry
c1e21719a2 core: avoid bumping hard rlimits, restore on fork
ref #6584
2024-06-19 18:36:40 +02:00
Vaxry
def5fcb212 damageRing: move to hyprland impl
A small wlroots utility we were still using.
2024-06-19 18:25:25 +02:00
Mihai Fufezan
65f04f265c flake.lock: update 2024-06-19 18:36:50 +03:00
Vaxry
6d21014a50 core: fix no-pch build 2024-06-19 16:29:00 +02:00
Lucas Reis
20a465f69d pointer: use software rendering when monitor is mirrored (#6587)
* pointer_manager: add lock/unlock software wrappers that receive the raw pointer

* monitor: lock/unlock software pointer rendering when adding/removing mirrored screens

* use relative path in includes
2024-06-19 16:24:28 +02:00
Vaxry
fb15b7aa2a core: Move to hyprutils for Math
Moves CRegion, CBox and Vector2D over to hyprutils.

Requires hyprutils>=0.1.4
2024-06-19 16:20:15 +02:00
random2907
6e5804b53d hyprctl: fix zsh completion (#6467)
Co-authored-by: random2907 <yarnjeetyadav1234567890@gmail.com>
2024-06-19 09:20:49 +03:00
Vaxry
e0e3c4c6ae compositor: bump nofile rlimits on launch
ref #6584
2024-06-18 21:53:01 +02:00
Vaxry
b98e0876d3 hyprctl: avoid using select()
move to poll()

ref #6584
2024-06-18 21:53:01 +02:00
Aqa-Ib
236150b3c5 github: reword bug or regression (#6520) 2024-06-18 18:06:14 +03:00
Vaxry
d1340bd1d8 keybinds: ignore missing keysyms if no other methods match
fixes #6548
2024-06-17 17:53:51 +02:00
Tom Englund
28ce0e0f80 misc: a few compiler level performance optimisations (#6559)
* window: use const references instead of copies

use const references instead of wasteful copies and make the = operator
check for self assignment and return early. also use const in all the
other operators.

* listener: pass std::function as const reference

instead of copies pass the std::functions as const references.

* config: dont unnecessarily convert to c_str

getHyprlangConfigValuePtr wants an std::string and we already have an
std::string, dont convert it to a c_str only for it to be converted back
to an std::string.

* buffer: pass attributes as const reference

pass attributes as const reference instead of copies.
2024-06-17 17:37:36 +02:00
Vaxry
a9c7a0830f data-device: minor fixes
send leave after drop, improve checks in completeDrag
2024-06-17 16:14:45 +02:00
Vaxry
785d062887 seat: track pressed pointer buttons
releases them on leave, unless there is a dnd going on
2024-06-17 16:07:32 +02:00
Vaxry
1360677478 subcompositor/renderer: fixup handling of subsurfaces below the main one
some apps (notably vlc 4) place a subsurface below the main surface (which is kinda cursed) but we have to accomodate for that
2024-06-17 12:42:39 +02:00
Mihai Fufezan
14ab0ecc5e Nix: don't strip in debug builds
Strip in Release builds, as the non-stripped binary is almost 500MB.
2024-06-17 13:14:27 +03:00
Mihai Fufezan
9cb3bf1cac Nix: tidy up derivation 2024-06-17 13:03:59 +03:00
Vaxry
b15be9c77d xwayland: do not set a new data source if it has no MIMEs
ref #6247
2024-06-16 21:34:17 +02:00
Vaxry
d5ef10abf4 data-device: properly abort drag on missing device
sometimes there is no focused device (e.g. when dnd'ing on nothing or xwayland) in which case abort would fail to send cancelled to the source.

ref #6543
2024-06-16 20:56:50 +02:00
Vaxry
172ee1cada data-device: minor fixups
ref #6543

firefox needs a re-enter after a dnd

don't destroy dnd on an offer destroy, it's not valid
2024-06-16 20:36:55 +02:00
Dashie
738530e62e xdg-shell: Continue transform of popup until size fits (#6521) 2024-06-16 20:01:08 +02:00
Vaxry
069a21a34e xwayland: force default plain mime atoms on known types
ref #6247
2024-06-16 19:52:07 +02:00
Vaxry
2031af82fa wl_data_device: send drop_performed in completeDrag
ref #6509
2024-06-16 17:41:16 +02:00
Vaxry
d0a6fa7aa6 wl_seat: accomodate for apps late-binding seat resources
Sends enter events when an app binds wl_keyboard or wl_pointer later than it should. Fixes some buggy apps.

Fixes #6131
2024-06-16 17:04:10 +02:00
Vaxry
648ac8a00b xdg-shell: properly check for resource version for TILED and SUSPENDED states
fixes #6535
2024-06-16 16:46:22 +02:00
memchr
43c75f17eb input: add cursor:warp_on_changeworkspace (#6480)
* input: add cursor:warp_on_changeworkspace

If enabled, warp the cursor to the last focused window on the workspace in the `changeworkspace' dispatcher, except if the cursor is currently on the WLR top layer.

Respect persistent warps.

* warp_on_change_workspace: check if focused layer is a window.
2024-06-16 16:42:32 +02:00
Vaxry
1b5444494d seat/dnd: unfocus pointer from surfaces on dnd start
GTK is speshyal and requires this for functioning properly. Ugh.

It's technically not required by spec, f you gtk.

Ref #6509
2024-06-16 16:23:41 +02:00
memchr
3eaf35f1e2 hyprland.conf: update master section (#6537) 2024-06-16 16:44:13 +03:00
Vaxry
2566d81884 xwayland: fixup unfocus atom conditions
ref #6468
2024-06-16 12:38:09 +02:00
Vaxry
1f5fd7e64a hyprpm: add --no-shallow 2024-06-15 21:46:36 +02:00
Vaxry
908bec1564 wl_seat: send repeat data from current keyboard on bind
ref #6515
2024-06-15 21:24:34 +02:00
memchr
89f795da98 master: refine master layout new window handling (#6479)
* ## Open window relative to active window

`new_on_active`:
  - `none` (default):
  - `before`: above of the focused window
  - `after`: below the focused window

If the focused window is the solo master window, or the new window replaces master, this option has no effect and new_on_top are respected.

## Refine new window status control

**BREAKING CHANGE**: new_is_master removed in favour of new variable

`new_status`:
  - `slave` (default): new window open as slave
  - `master`: new window open as master
  - `inherit`: new window inherit status from active window, i.e. when the focused window is master, new window will become new master, otherwise new window are added to slaves

* refactor: rename a few variables
2024-06-15 21:17:38 +02:00
Vaxry
91fe58f8f2 window: improve swallowing functionality
cleanups, fixes, etc.

ref #6095
2024-06-15 18:20:41 +02:00
Vaxry
77f44bfcab output: avoid crashes when binding a defunct wl_output global
ref #6508
2024-06-15 17:56:44 +02:00
Vaxry
6c24dc0bb1 xdg-shell: fixup xdg-positioner's pointForAnchor with non-corner points
fixes #6157
2024-06-15 17:43:39 +02:00
Vaxry
46ef6653be data-device: abort drag on unaccepted offers
fixes #6509
2024-06-15 17:33:21 +02:00
Vaxry
fb82f6bcd7 animations: fix overriding direction for slide
fixes #6512
2024-06-15 16:31:35 +02:00
Vaxry
32aca88752 keybinds: add custom event dispatcher
fixes #3439
2024-06-15 16:20:00 +02:00
Vaxry
df0c014ba0 xwayland: use safeRemove for removing files
fixes #6514
2024-06-15 16:06:07 +02:00
vaxerski
cb63398f07 [gha] Nix: update inputs 2024-06-14 20:00:53 +00:00
Vaxry
2f278dc883 egl: fixup format modifier lookups with implicit modifiers
ref #6485
2024-06-14 21:59:21 +02:00
Vaxry
12ce06f39b format: fix flipped r/b channels on legacy_renderer
We don't wanna use an extension, but for gles2 there is no other option.

fixes #6465
2024-06-14 19:10:12 +02:00
Vaxry
a357fa3e0a window: use effective damage for tearing re-schedules
fixes #6377
2024-06-14 16:45:41 +02:00
UjinT34
a9d53a2252 vrr: add option to fix mouse breaking vrr (#6483)
* option to fix mouse breaking vrr

* skip damage on mouse move

* remove this-> & cleanup

* add cursor:min_refresh_rate to avoid cursor freezing

* run clang-format

---------

Co-authored-by: UjinT34 <ujin@uvpn.ru>
2024-06-14 13:45:32 +02:00
Alexander
b2590b58c5 hyprctl: added --follow option to rolliglog (#6325)
Co-authored-by: Крылов Александр <aleksandr.krylov@hyperus.team>
2024-06-14 12:11:40 +02:00
outfoxxed
9cd5b3587c layerSurface: fix layer being refocused every commit with on_demand (#6487)
* layerSurface: fix layer being refocused every commit with on_demand

Fixes #6477

The surface will now only receive focus when its keyboard
interactivity is more than the previous keyboard interactivity in the
order none -> on_demand -> exclusive.

* layerSurface: only kb focus if becoming exclusive
2024-06-14 11:52:37 +02:00
phonetic112
8055b1c00a misc: Fix build warnings (#6486) 2024-06-13 23:23:23 +02:00
Vaxry
5de273a144 xwayland: drop some spammy logs to trace
fixes #6478
2024-06-13 17:32:32 +02:00
Jan Beich
4842eb83b4 helpers: make shm_open() portable after 8bcccf9f0f (#6471)
https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html
https://man.freebsd.org/shm_open/2
https://www.man7.org/linux/man-pages/man3/shm_open.3.html
2024-06-13 14:20:14 +02:00
Tom Englund
e6d10539af core: fix a few small memory leaks on exit (#6470)
* renderer: add destructor and destroy event source

add destructor and destroy the event source.
one less leak on exit of compositor reported by asan.

* compositor: cleanup eventloop on exit

destruct hyprctl to release the event sources, and properly cleanup the
event loop on exit of compositor. less leaks on exit reported by asan

* threadmgr: destroy event source on destruction

destroy the event source on destruction.

* eventloopmgr: reset eventloopmgr on exit aswell

reset the eventloopmanager on exit of compositor and free the leaking
last idle frame on monitor destroy.
2024-06-13 12:08:02 +02:00
Vaxry
9e781040d9 props: bump version to 0.41.1 2024-06-13 11:54:06 +02:00
Yang, Ying-chao
a54f98c203 virtualkeyboard: check if VirtualKeyboard is valid before accessing client. (#6460)
This fixes crash when restarting fcitx (#6378)
2024-06-13 11:33:47 +02:00
Vaxry
d677ac6f87 hyprpm: print all types of cmake errors during configure 2024-06-13 11:33:20 +02:00
Vaxry
a9d7befc36 formats: fixup for legacy_renderer builds 2024-06-12 23:29:24 +02:00
Vaxry
0e18da8467 foreign-toplevel: fixup output resource finding
fixes #6457
2024-06-12 23:28:52 +02:00
Vaxry
18ee9ece9c layershell: minor fixes to re-mapping of layers
ref #2012
2024-06-12 22:57:06 +02:00
Ikalco
38132ffaf5 renderer: properly software lock cursors with zoom_factor (#6434) 2024-06-12 19:28:52 +02:00
Vaxry
a99f314106 input: fallback to main surface if not found on window
fixes #6421
2024-06-12 18:39:52 +02:00
Vaxry
9d7d5ec3c8 seatmgr: fix missing nullcheck in updateActiveKeyboardData
sometimes we may set a keyboard that's about-to-be-deleted, we might as well check for that

additionally avoid setting null keyboards altogether
2024-06-12 17:03:12 +02:00
vaxerski
c7e85e26f7 seat: fixup touch event handling
fixes #6353
2024-06-12 16:49:26 +02:00
Vaxry
1bae19ce85 datadevice: only send actions for ver >= 3
fixes #6444
2024-06-12 16:16:27 +02:00
Vaxry
f687105eff compositor: update suspended states on moveworkspacetomonitor
fixes #6417
2024-06-12 16:02:25 +02:00
MightyPlaza
32283ed706 groupbar: fix groupbar position rounding (#6433)
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
2024-06-12 15:56:35 +02:00
Moritz G
8412ffcc42 keybinds: fix bindm (#6429)
* fixed mouse dispatcher

* no brakets

* move command up
2024-06-11 23:02:29 +02:00
MightyPlaza
b6bf4afb48 layer: don't close special ws when restoring focus (#6424)
modified:   src/Compositor.cpp
modified:   src/Compositor.hpp
modified:   src/managers/input/InputManager.cpp
2024-06-11 22:56:35 +02:00
Moritz G
e1b05f8eaf binds: Add description to key binds (#6358)
---------

Co-authored-by: Yusuf Duran <firatyusuf.d@gmail.com>
2024-06-11 19:49:54 +02:00
outfoxxed
21b9e31bf4 layershell: Fix keyboard focus grabs (#4968) (#6394) 2024-06-11 19:35:30 +02:00
Maximilian Seidler
1c388e52fb session-lock: fix refocus after unlocking (#6423) 2024-06-11 17:18:51 +02:00
Vaxry
8c64a4bad7 core: move to hyprutils for utils (#6385)
* core: move to hyprutils for utils

Nix: add hyprutils dep

* Meson: add hyprutils dep

* flake.lock: update

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-06-11 17:17:45 +02:00
Vaxry
1f46296ea0 deps: update wlroots 2024-06-11 17:12:24 +02:00
outfoxxed
809820921d sessionLock: fix focus not being tied to mouse (#6414) 2024-06-11 17:11:15 +02:00
outfoxxed
90d0097716 input: fix input regions being ignored on ls-es (#6413) 2024-06-11 17:01:25 +02:00
zakk4223
b17381eb81 groupbar: Don't apply monitor scale twice to groupbar text (#6411) 2024-06-11 17:00:50 +02:00
Jan Beich
811429bfd4 wayland: consistently check mmap error after 6967a31450 (#6402)
mmap() returns MAP_FAILED on error, not nullptr.
2024-06-10 22:31:03 +02:00
284 changed files with 11316 additions and 8981 deletions

View File

@@ -5,18 +5,21 @@ body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Before opening a new issue, take a moment to search through the current open ones. ## Before opening a new issue, please take a moment to search through the current open and closed issues to check if it already exists.
--- ---
- type: dropdown - type: dropdown
id: type id: type
attributes: attributes:
label: Bug or Regression? label: Regression?
description: Is this a bug or a 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: options:
- Bug - "Yes"
- Regression - "No"
validations: validations:
required: true required: true

View File

@@ -34,6 +34,7 @@ runs:
libglvnd \ libglvnd \
libinput \ libinput \
libliftoff \ libliftoff \
libxcursor \
libxcvt \ libxcvt \
libxfont2 \ libxfont2 \
libxkbcommon \ libxkbcommon \
@@ -68,6 +69,16 @@ runs:
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
cmake --install build cmake --install build
- name: Get hyprutils-git
shell: bash
run: |
git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build
- name: Get aquamarine-git
shell: bash
run: |
git clone https://github.com/hyprwm/aquamarine && cd aquamarine && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target aquamarine && cmake --install build
- name: Get Xorg pacman pkgs - name: Get Xorg pacman pkgs
shell: bash shell: bash
if: inputs.INSTALL_XORG_PKGS == 'true' if: inputs.INSTALL_XORG_PKGS == 'true'

View File

@@ -3,6 +3,7 @@ name: Build Hyprland
on: [push, pull_request, workflow_dispatch] on: [push, pull_request, workflow_dispatch]
jobs: jobs:
gcc: gcc:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Build Hyprland (Arch)" name: "Build Hyprland (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@@ -44,6 +45,7 @@ jobs:
path: Hyprland.tar.xz path: Hyprland.tar.xz
meson: meson:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Build Hyprland with Meson (Arch)" name: "Build Hyprland with Meson (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@@ -64,6 +66,7 @@ jobs:
run: ninja -C build run: ninja -C build
no-pch: no-pch:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Build Hyprland without precompiled headers (Arch)" name: "Build Hyprland without precompiled headers (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@@ -83,6 +86,7 @@ jobs:
run: make nopch run: make nopch
noxwayland: noxwayland:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Build Hyprland in pure Wayland (Arch)" name: "Build Hyprland in pure Wayland (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
@@ -103,6 +107,7 @@ jobs:
run: make release run: make release
clang-format: clang-format:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Code Style (Arch)" name: "Code Style (Arch)"
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:

View File

@@ -15,14 +15,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clone repository - name: Clone repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
ref: ${{ github.ref }} ref: ${{ github.ref }}
submodules: recursive submodules: recursive
- uses: cachix/install-nix-action@v26 - uses: cachix/install-nix-action@v27
- uses: DeterminateSystems/magic-nix-cache-action@main - uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v12 - uses: cachix/cachix-action@v15
with: with:
name: hyprland name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'

View File

@@ -9,7 +9,7 @@ jobs:
secrets: inherit secrets: inherit
build: build:
if: always() && !cancelled() && !contains(needs.*.result, 'failure') if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) && !contains(needs.*.result, 'failure')
needs: update-inputs needs: update-inputs
uses: ./.github/workflows/nix-build.yml uses: ./.github/workflows/nix-build.yml
secrets: inherit secrets: inherit

View File

@@ -4,6 +4,7 @@ on: [push, pull_request]
jobs: jobs:
flawfinder: flawfinder:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: Flawfinder Checks name: Flawfinder Checks
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:

8
.gitignore vendored
View File

@@ -7,6 +7,9 @@ cmake_install.cmake
install_manifest.txt install_manifest.txt
compile_commands.json compile_commands.json
CTestTestfile.cmake CTestTestfile.cmake
CPackConfig.cmake
CPackSourceConfig.cmake
hyprland.pc
_deps _deps
build/ build/
@@ -15,6 +18,9 @@ result*
/.idea/ /.idea/
.envrc .envrc
.cache .cache
.direnv
/.cmake/
/.worktree/
*.o *.o
protocols/*.c* protocols/*.c*
@@ -31,5 +37,3 @@ gmon.out
PKGBUILD PKGBUILD
src/version.h src/version.h
.direnv

4
.gitmodules vendored
View File

@@ -7,7 +7,3 @@
[submodule "subprojects/tracy"] [submodule "subprojects/tracy"]
path = subprojects/tracy path = subprojects/tracy
url = https://github.com/wolfpld/tracy url = https://github.com/wolfpld/tracy
[submodule "subprojects/wlroots-hyprland"]
path = subprojects/wlroots-hyprland
url = https://github.com/hyprwm/wlroots-hyprland
ignore = dirty

View File

@@ -1,17 +1,16 @@
cmake_minimum_required(VERSION 3.27) cmake_minimum_required(VERSION 3.27)
include(CheckIncludeFile)
include(ExternalProject)
include(GNUInstallDirs)
# Get version # Get version
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/props.json PROPS) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
string(JSON VER GET ${PROPS} version) string(STRIP ${VER_RAW} VER)
project(Hyprland project(
DESCRIPTION "A Modern C++ Wayland Compositor" Hyprland
VERSION ${VER} DESCRIPTION "A Modern C++ Wayland Compositor"
) VERSION ${VER})
include(CheckIncludeFile)
include(GNUInstallDirs)
set(HYPRLAND_VERSION ${VER}) set(HYPRLAND_VERSION ${VER})
set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(PREFIX ${CMAKE_INSTALL_PREFIX})
@@ -22,77 +21,57 @@ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
message(STATUS "Gathering git info") message(STATUS "Gathering git info")
# Get git info # Get git info hash and branch
# hash and branch execute_process(COMMAND ./scripts/generateVersion.sh
execute_process( WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# udis # udis
add_subdirectory("subprojects/udis86") add_subdirectory("subprojects/udis86")
# wlroots
message(STATUS "Setting up wlroots")
if(CMAKE_BUILD_TYPE) if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
if(BUILDTYPE_LOWER STREQUAL "release") if(BUILDTYPE_LOWER STREQUAL "release")
# Pass. # Pass.
elseif(BUILDTYPE_LOWER STREQUAL "debug") elseif(BUILDTYPE_LOWER STREQUAL "debug")
# Pass. # Pass.
elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo") elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
set(BUILDTYPE_LOWER "debugoptimized") set(BUILDTYPE_LOWER "debugoptimized")
elseif(BUILDTYPE_LOWER STREQUAL "minsizerel") elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
set(BUILDTYPE_LOWER "minsize") set(BUILDTYPE_LOWER "minsize")
elseif(BUILDTYPE_LOWER STREQUAL "none") elseif(BUILDTYPE_LOWER STREQUAL "none")
set(BUILDTYPE_LOWER "plain") set(BUILDTYPE_LOWER "plain")
else() else()
set(BUILDTYPE_LOWER "release")
endif()
else()
set(BUILDTYPE_LOWER "release") set(BUILDTYPE_LOWER "release")
endif()
else()
set(BUILDTYPE_LOWER "release")
endif() endif()
ExternalProject_Add(
wlroots-hyprland
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland
CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$<IF:$<BOOL:${NO_XWAYLAND}>,disabled,enabled> -Dexamples=false -Drenderers=gles2 -Dbackends=drm,libinput $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none>
BUILD_COMMAND ninja -C build
BUILD_ALWAYS true
BUILD_IN_SOURCE true
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a
INSTALL_COMMAND echo "wlroots-hyprland: install not needed"
)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner)
message(STATUS "Found WaylandScanner at ${WaylandScanner}")
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Configuring Hyprland in Debug with CMake") message(STATUS "Configuring Hyprland in Debug with CMake")
add_compile_definitions(HYPRLAND_DEBUG) add_compile_definitions(HYPRLAND_DEBUG)
else() else()
add_compile_options(-O3) add_compile_options(-O3)
message(STATUS "Configuring Hyprland in Release with CMake") message(STATUS "Configuring Hyprland in Release with CMake")
endif() endif()
include_directories( include_directories(. "src/" "subprojects/udis86/" "protocols/")
.
"src/"
"subprojects/wlroots-hyprland/include/"
"subprojects/wlroots-hyprland/build/include/"
"subprojects/udis86/"
"protocols/")
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
add_compile_definitions(WLR_USE_UNSTABLE) add_compile_options(
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wall
-Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith -Wextra
-fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) -Wno-unused-parameter
-Wno-unused-value
-Wno-missing-field-initializers
-Wno-narrowing
-Wno-pointer-arith
-fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=)
set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE) set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
@@ -102,19 +81,45 @@ message(STATUS "Checking deps...")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
if(LEGACY_RENDERER) if(LEGACY_RENDERER)
set(GLES_VERSION "GLES2") set(GLES_VERSION "GLES2")
else() else()
set(GLES_VERSION "GLES3") set(GLES_VERSION "GLES3")
endif() endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(deps REQUIRED IMPORTED_TARGET pkg_check_modules(
xkbcommon uuid hyprctl_deps
wayland-server wayland-client wayland-cursor wayland-protocols REQUIRED
cairo pango pangocairo pixman-1 IMPORTED_TARGET
libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm hyprutils>=0.2.1)
hyprlang>=0.3.2 hyprcursor>=0.1.7
) pkg_check_modules(
deps
REQUIRED
IMPORTED_TARGET
aquamarine
xkbcommon
uuid
wayland-server
wayland-client
wayland-cursor
wayland-protocols
cairo
pango
pangocairo
pixman-1
xcursor
libdrm
libinput
hwdata
libseat
libdisplay-info
libliftoff
libudev
gbm
hyprlang>=0.3.2
hyprcursor>=0.1.7
hyprutils>=0.2.1)
find_package(hyprwayland-scanner 0.3.10 REQUIRED) find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -122,85 +127,97 @@ file(GLOB_RECURSE SRCFILES "src/*.cpp")
set(TRACY_CPP_FILES "") set(TRACY_CPP_FILES "")
if(USE_TRACY) if(USE_TRACY)
set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp") set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES}) message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
endif() endif()
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
add_dependencies(Hyprland wlroots-hyprland)
set(USE_GPROF ON) set(USE_GPROF ON)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Setting debug flags") message(STATUS "Setting debug flags")
if (WITH_ASAN) if(WITH_ASAN)
message(STATUS "Enabling ASan") message(STATUS "Enabling ASan")
target_link_libraries(Hyprland asan) target_link_libraries(Hyprland asan)
target_compile_options(Hyprland PUBLIC -fsanitize=address) target_compile_options(Hyprland PUBLIC -fsanitize=address)
endif()
if(USE_TRACY)
message(STATUS "Tracy is turned on")
option(TRACY_ENABLE "" ON)
option(TRACY_ON_DEMAND "" ON)
add_subdirectory(subprojects/tracy)
target_link_libraries(Hyprland Tracy::TracyClient)
if(USE_TRACY_GPU)
message(STATUS "Tracy GPU Profiling is turned on")
add_compile_definitions(USE_TRACY_GPU)
endif() endif()
endif()
if(USE_TRACY) add_compile_options(-fno-pie -fno-builtin)
message(STATUS "Tracy is turned on") add_link_options(-no-pie -fno-builtin)
if(USE_GPROF)
option( TRACY_ENABLE "" ON) add_compile_options(-pg)
option( TRACY_ON_DEMAND "" ON) add_link_options(-pg)
add_subdirectory (subprojects/tracy) endif()
target_link_libraries(Hyprland Tracy::TracyClient)
if(USE_TRACY_GPU)
message(STATUS "Tracy GPU Profiling is turned on")
add_compile_definitions(USE_TRACY_GPU)
endif()
endif()
add_compile_options(-fno-pie -fno-builtin)
add_link_options(-no-pie -fno-builtin)
if(USE_GPROF)
add_compile_options(-pg)
add_link_options(-pg)
endif()
endif() endif()
check_include_file("execinfo.h" EXECINFOH) check_include_file("execinfo.h" EXECINFOH)
if(EXECINFOH) if(EXECINFOH)
message(STATUS "Configuration supports execinfo") message(STATUS "Configuration supports execinfo")
add_compile_definitions(HAS_EXECINFO) add_compile_definitions(HAS_EXECINFO)
endif() endif()
include(CheckLibraryExists) include(CheckLibraryExists)
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO) check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
if(HAVE_LIBEXECINFO) if(HAVE_LIBEXECINFO)
target_link_libraries(Hyprland execinfo) target_link_libraries(Hyprland execinfo)
endif() endif()
check_include_file("sys/timerfd.h" HAS_TIMERFD) check_include_file("sys/timerfd.h" HAS_TIMERFD)
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim) pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
if(NOT HAS_TIMERFD AND epoll_FOUND) if(NOT HAS_TIMERFD AND epoll_FOUND)
target_link_libraries(Hyprland PkgConfig::epoll) target_link_libraries(Hyprland PkgConfig::epoll)
endif() endif()
if(LEGACY_RENDERER) if(LEGACY_RENDERER)
message(STATUS "Using the legacy GLES2 renderer!") message(STATUS "Using the legacy GLES2 renderer!")
add_compile_definitions(LEGACY_RENDERER) add_compile_definitions(LEGACY_RENDERER)
endif() endif()
if(NO_XWAYLAND) if(NO_XWAYLAND)
message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!") message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
add_compile_definitions(NO_XWAYLAND) add_compile_definitions(NO_XWAYLAND)
else() else()
message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...") message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh xcb-errors) pkg_check_modules(
target_link_libraries(Hyprland PkgConfig::xdeps) xdeps
REQUIRED
IMPORTED_TARGET
xcb
xwayland
xcb-util
xcb-render
xcb-xfixes
xcb-icccm
xcb-composite
xcb-res
xcb-ewmh
xcb-errors)
target_link_libraries(Hyprland PkgConfig::xdeps)
endif() endif()
if(NO_SYSTEMD) if(NO_SYSTEMD)
message(STATUS "SYSTEMD support is disabled...") message(STATUS "SYSTEMD support is disabled...")
else() else()
message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
add_compile_definitions(USES_SYSTEMD) add_compile_definitions(USES_SYSTEMD)
endif() endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})
@@ -209,7 +226,8 @@ include(CPack)
message(STATUS "Setting precompiled headers") message(STATUS "Setting precompiled headers")
target_precompile_headers(Hyprland PRIVATE $<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>) target_precompile_headers(Hyprland PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:src/pch/pch.hpp>)
message(STATUS "Setting link libraries") message(STATUS "Setting link libraries")
@@ -218,104 +236,87 @@ target_link_libraries(Hyprland rt PkgConfig::deps)
# used by `make installheaders`, to ensure the headers are generated # used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers) add_custom_target(generate-protocol-headers)
function(protocol protoPath protoName external) function(protocolnew protoPath protoName external)
if (external) if(external)
set(path ${CMAKE_SOURCE_DIR}/${protoPath}) set(path ${CMAKE_SOURCE_DIR}/${protoPath})
else() else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif() endif()
add_custom_command(
add_custom_command( OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h COMMAND hyprwayland-scanner ${path}/${protoName}.xml
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/protocols/
) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
add_custom_command( target_sources(Hyprland PRIVATE protocols/${protoName}.cpp
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c protocols/${protoName}.hpp)
COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c target_sources(generate-protocol-headers
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
)
target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c)
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h)
endfunction()
function(protocolNew protoPath protoName external)
if (external)
set(path ${CMAKE_SOURCE_DIR}/${protoPath})
else()
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
endif()
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
target_sources(Hyprland PRIVATE protocols/${protoName}.cpp protocols/${protoName}.hpp)
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
endfunction() endfunction()
function(protocolWayland) function(protocolWayland)
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ COMMAND hyprwayland-scanner --wayland-enums
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) target_sources(generate-protocol-headers
PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
endfunction() endfunction()
target_link_libraries(Hyprland target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads
${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a libudis86 uuid)
OpenGL::EGL
OpenGL::GL
Threads::Threads
libudis86
uuid
)
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) protocolnew("subprojects/hyprland-protocols/protocols"
protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) "hyprland-global-shortcuts-v1" true)
protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) protocolnew("unstable/text-input" "text-input-unstable-v1" false)
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) protocolnew("subprojects/hyprland-protocols/protocols"
"hyprland-toplevel-export-v1" true)
protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
protocolnew("protocols" "wlr-gamma-control-unstable-v1" true)
protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
protocolnew("protocols" "wlr-output-power-management-unstable-v1" true)
protocolnew("protocols" "virtual-keyboard-unstable-v1" true)
protocolnew("protocols" "wlr-virtual-pointer-unstable-v1" true)
protocolnew("protocols" "input-method-unstable-v2" true)
protocolnew("protocols" "wlr-output-management-unstable-v1" true)
protocolnew("protocols" "kde-server-decoration" true)
protocolnew("protocols" "wlr-data-control-unstable-v1" true)
protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1"
true)
protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
protocolnew("protocols" "wayland-drm" true)
protocolnew("staging/tearing-control" "tearing-control-v1" false)
protocolnew("staging/fractional-scale" "fractional-scale-v1" false)
protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false)
protocolnew("staging/cursor-shape" "cursor-shape-v1" false)
protocolnew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false)
protocolnew("unstable/relative-pointer" "relative-pointer-unstable-v1" false)
protocolnew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false)
protocolnew("staging/alpha-modifier" "alpha-modifier-v1" false)
protocolnew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1"
false)
protocolnew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false)
protocolnew("unstable/keyboard-shortcuts-inhibit"
"keyboard-shortcuts-inhibit-unstable-v1" false)
protocolnew("unstable/text-input" "text-input-unstable-v3" false)
protocolnew("unstable/pointer-constraints" "pointer-constraints-unstable-v1"
false)
protocolnew("staging/xdg-activation" "xdg-activation-v1" false)
protocolnew("staging/ext-idle-notify" "ext-idle-notify-v1" false)
protocolnew("staging/ext-session-lock" "ext-session-lock-v1" false)
protocolnew("stable/tablet" "tablet-v2" false)
protocolnew("stable/presentation-time" "presentation-time" false)
protocolnew("stable/xdg-shell" "xdg-shell" false)
protocolnew("unstable/primary-selection" "primary-selection-unstable-v1" false)
protocolnew("staging/xwayland-shell" "xwayland-shell-v1" false)
protocolnew("stable/viewporter" "viewporter" false)
protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
protocolnew("staging/drm-lease" "drm-lease-v1" false)
protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) protocolwayland()
protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
protocolNew("protocols" "wlr-output-power-management-unstable-v1" true)
protocolNew("protocols" "virtual-keyboard-unstable-v1" true)
protocolNew("protocols" "wlr-virtual-pointer-unstable-v1" true)
protocolNew("protocols" "input-method-unstable-v2" true)
protocolNew("protocols" "wlr-output-management-unstable-v1" true)
protocolNew("protocols" "kde-server-decoration" true)
protocolNew("protocols" "wlr-data-control-unstable-v1" true)
protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true)
protocolNew("protocols" "wlr-layer-shell-unstable-v1" true)
protocolNew("protocols" "wayland-drm" true)
protocolNew("staging/tearing-control" "tearing-control-v1" false)
protocolNew("staging/fractional-scale" "fractional-scale-v1" false)
protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false)
protocolNew("staging/cursor-shape" "cursor-shape-v1" false)
protocolNew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false)
protocolNew("unstable/relative-pointer" "relative-pointer-unstable-v1" false)
protocolNew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false)
protocolNew("staging/alpha-modifier" "alpha-modifier-v1" false)
protocolNew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false)
protocolNew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false)
protocolNew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false)
protocolNew("unstable/text-input" "text-input-unstable-v3" false)
protocolNew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" false)
protocolNew("staging/xdg-activation" "xdg-activation-v1" false)
protocolNew("staging/ext-idle-notify" "ext-idle-notify-v1" false)
protocolNew("staging/ext-session-lock" "ext-session-lock-v1" false)
protocolNew("stable/tablet" "tablet-v2" false)
protocolNew("stable/presentation-time" "presentation-time" false)
protocolNew("stable/xdg-shell" "xdg-shell" false)
protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false)
protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false)
protocolNew("stable/viewporter" "viewporter" false)
protocolNew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
protocolWayland()
# tools # tools
add_subdirectory(hyprctl) add_subdirectory(hyprctl)
@@ -324,60 +325,52 @@ add_subdirectory(hyprpm)
# binary and symlink # binary and symlink
install(TARGETS Hyprland) install(TARGETS Hyprland)
install(CODE "execute_process( \ install(
CODE "execute_process( \
COMMAND ${CMAKE_COMMAND} -E create_symlink \ COMMAND ${CMAKE_COMMAND} -E create_symlink \
${CMAKE_INSTALL_BINDIR}/Hyprland \ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
${CMAKE_INSTALL_BINDIR}/hyprland ${CMAKE_INSTALL_FULL_BINDIR}/hyprland
)" )")
)
# session file # session file
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
DESTINATION ${CMAKE_INSTALL_DATADIR}/wayland-sessions) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
# allow Hyprland to find wallpapers
add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}")
# wallpapers # wallpapers
file(GLOB_RECURSE WALLPAPERS "assets/wall*") file(GLOB_RECURSE WALLPAPERS "assets/wall*")
install(FILES ${WALLPAPERS} install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland)
# default config # default config
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf
DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
# portal config # portal config
install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf
DESTINATION ${CMAKE_INSTALL_DATADIR}/xdg-desktop-portal) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/xdg-desktop-portal)
# man pages # man pages
file(GLOB_RECURSE MANPAGES "docs/*.1") file(GLOB_RECURSE MANPAGES "docs/*.1")
install(FILES ${MANPAGES} install(FILES ${MANPAGES} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
# pkgconfig entry # pkgconfig entry
install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
# wlroots headers
set(HEADERS_WLR "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/include/wlr")
install(DIRECTORY ${HEADERS_WLR}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING PATTERN "*.h")
# config.h and version.h
set(HEADERS_WLR_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/build/include/wlr")
install(DIRECTORY ${HEADERS_WLR_ROOT}/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland/wlr
FILES_MATCHING PATTERN "*.h")
# protocol headers # protocol headers
set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols") set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols")
install(DIRECTORY ${HEADERS_PROTO} install(
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland DIRECTORY ${HEADERS_PROTO}
FILES_MATCHING PATTERN "*.h*") DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING
PATTERN "*.h*")
# hyprland headers # hyprland headers
set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src") set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src")
install(DIRECTORY ${HEADERS_SRC} install(
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland DIRECTORY ${HEADERS_SRC}
FILES_MATCHING PATTERN "*.h*") DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING
PATTERN "*.h*")

View File

@@ -27,7 +27,6 @@ nopch:
clear: clear:
rm -rf build rm -rf build
rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp
rm -rf ./subprojects/wlroots-hyprland/build
all: all:
$(MAKE) clear $(MAKE) clear
@@ -42,7 +41,7 @@ uninstall:
pluginenv: pluginenv:
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n" @echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
@exit 1 @exit 1
installheaders: installheaders:
@if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi @if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
@@ -50,14 +49,11 @@ installheaders:
rm -fr ${PREFIX}/include/hyprland rm -fr ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland/protocols mkdir -p ${PREFIX}/include/hyprland/protocols
mkdir -p ${PREFIX}/include/hyprland/wlr
mkdir -p ${PREFIX}/share/pkgconfig mkdir -p ${PREFIX}/share/pkgconfig
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 -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
cd subprojects/wlroots-hyprland/include/wlr && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../..
cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../..
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
@@ -88,7 +84,7 @@ asan:
@pidof Hyprland > /dev/null && exit 1 || echo "" @pidof Hyprland > /dev/null && exit 1 || echo ""
rm -rf ./wayland rm -rf ./wayland
git reset --hard #git reset --hard
@echo -en "If you want to apply a patch, input its path (leave empty for none):\n" @echo -en "If you want to apply a patch, input its path (leave empty for none):\n"
@read patchvar @read patchvar

View File

@@ -13,10 +13,10 @@
<br> <br>
Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks. Hyprland is a 100% independent, dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
It provides the latest Wayland features, is highly customizable, has all the eyecandy, the most powerful plugins, It provides the latest Wayland features, is highly customizable, has all the eyecandy, the most powerful plugins,
easy IPC, much more QoL stuff than other wlr-based compositors and more... easy IPC, much more QoL stuff than other compositors and more...
<br> <br>
<br> <br>
@@ -37,7 +37,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
- All of the eyecandy: gradient borders, blur, animations, shadows and much more - All of the eyecandy: gradient borders, blur, animations, shadows and much more
- A lot of customization - A lot of customization
- Much more QoL stuff than other wlr-based compositors - 100% independent, no wlroots, no libweston, no kwin, no mutter.
- Custom bezier curves for the best animations - Custom bezier curves for the best animations
- Powerful plugin support - Powerful plugin support
- Built-in plugin manager - Built-in plugin manager
@@ -48,7 +48,6 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
- Config reloaded instantly upon saving - Config reloaded instantly upon saving
- Fully dynamic workspaces - Fully dynamic workspaces
- Two built-in layouts and more available as plugins - Two built-in layouts and more available as plugins
- Uses forked wlroots with QoL patches
- Global keybinds passed to your apps of choice - Global keybinds passed to your apps of choice
- Tiling/pseudotiling/floating/fullscreen windows - Tiling/pseudotiling/floating/fullscreen windows
- Special workspaces (scratchpads) - Special workspaces (scratchpads)
@@ -86,7 +85,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
<br> <br>
**[wlroots]** - *For their amazing library* **[wlroots]** - *For powering Hyprland in the past*
**[tinywl]** - *For showing how 2 do stuff* **[tinywl]** - *For showing how 2 do stuff*

1
VERSION Normal file
View File

@@ -0,0 +1 @@
0.42.0

View File

@@ -1,7 +1,7 @@
wallpapers = ['0', '1', '2'] wallpapers = ['0', '1', '2']
foreach type : wallpapers foreach type : wallpapers
install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime') install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime')
endforeach endforeach
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime') install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')

View File

@@ -32,6 +32,12 @@ Show command usage.
.TP .TP
\f[B]-c\f[R], \f[B]--config\f[R] \f[B]-c\f[R], \f[B]--config\f[R]
Specify config file to use. Specify config file to use.
.TP
\f[B]--socket\f[R]
Sets the Wayland socket name (for Wayland socket handover)
.TP
\f[B]--wayland-fd\f[R]
Sets the Wayland socket file descriptor (for Wayland socket handover)
.SH BUGS .SH BUGS
.TP .TP
Submit bug reports and request features online at: Submit bug reports and request features online at:

View File

@@ -41,6 +41,12 @@ OPTIONS
**-c**, **--config** **-c**, **--config**
Specify config file to use. Specify config file to use.
**--socket**
Sets the Wayland socket name (for Wayland socket handover)
**--wayland-fd**
Sets the Wayland socket file descriptor (for Wayland socket handover)
BUGS BUGS
==== ====

View File

@@ -125,7 +125,7 @@ dwindle {
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
master { master {
new_is_master = true new_status = master
} }
# https://wiki.hyprland.org/Configuring/Variables/#misc # https://wiki.hyprland.org/Configuring/Variables/#misc

View File

@@ -1,2 +1,2 @@
install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime') install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime')
install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime') install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime')

93
flake.lock generated
View File

@@ -1,5 +1,34 @@
{ {
"nodes": { "nodes": {
"aquamarine": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"hyprwayland-scanner": [
"hyprwayland-scanner"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1722347739,
"narHash": "sha256-rAoh+K6KG+b1DwSWtqRVocdojnH6nGk6q07mNltoUSM=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "7c3565f9bedc7cb601cc0baa14792247e4dc1d5a",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "aquamarine",
"type": "github"
}
},
"hyprcursor": { "hyprcursor": {
"inputs": { "inputs": {
"hyprlang": [ "hyprlang": [
@@ -13,11 +42,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1717181720, "lastModified": 1721330371,
"narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=", "narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c", "rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -38,11 +67,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1691753796, "lastModified": 1721326555,
"narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprland-protocols", "repo": "hyprland-protocols",
"rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -53,6 +82,9 @@
}, },
"hyprlang": { "hyprlang": {
"inputs": { "inputs": {
"hyprutils": [
"hyprutils"
],
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
@@ -61,11 +93,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1716473782, "lastModified": 1721324361,
"narHash": "sha256-+qLn4lsHU6iL3+HTo1gTQ1tWzet8K9h+IfVemzEQZj8=", "narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "87d5d984109c839482b88b4795db073eb9ed446f", "rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -74,6 +106,29 @@
"type": "github" "type": "github"
} }
}, },
"hyprutils": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1722098849,
"narHash": "sha256-D3wIZlBNh7LuZ0NaoCpY/Pvu+xHxIVtSN+KkWZYvvVs=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "5dcbbc1e3de40b2cecfd2007434d86e924468f1f",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprutils",
"type": "github"
}
},
"hyprwayland-scanner": { "hyprwayland-scanner": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -84,11 +139,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1717784906, "lastModified": 1721324119,
"narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=", "narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprwayland-scanner", "repo": "hyprwayland-scanner",
"rev": "0f30f9eca6e404130988554accbb64d1c9ec877d", "rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -99,11 +154,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1717602782, "lastModified": 1722185531,
"narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", "narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", "rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -115,8 +170,10 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"aquamarine": "aquamarine",
"hyprcursor": "hyprcursor", "hyprcursor": "hyprcursor",
"hyprlang": "hyprlang", "hyprlang": "hyprlang",
"hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner", "hyprwayland-scanner": "hyprwayland-scanner",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"systems": "systems", "systems": "systems",
@@ -152,11 +209,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1716290197, "lastModified": 1722365976,
"narHash": "sha256-1u9Exrc7yx9qtES2brDh7/DDZ8w8ap1nboIOAtCgeuM=", "narHash": "sha256-Khdm+mDzYA//XaU0M+hftod+rKr5q9SSHSEuiQ0/9ow=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "91e48d6acd8a5a611d26f925e51559ab743bc438", "rev": "7f2a77ddf60390248e2a3de2261d7102a13e5341",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -7,6 +7,14 @@
# <https://github.com/nix-systems/nix-systems> # <https://github.com/nix-systems/nix-systems>
systems.url = "github:nix-systems/default-linux"; systems.url = "github:nix-systems/default-linux";
aquamarine = {
url = "github:hyprwm/aquamarine";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
};
hyprcursor = { hyprcursor = {
url = "github:hyprwm/hyprcursor"; url = "github:hyprwm/hyprcursor";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
@@ -18,6 +26,13 @@
url = "github:hyprwm/hyprlang"; url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
};
hyprutils = {
url = "github:hyprwm/hyprutils";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
}; };
hyprwayland-scanner = { hyprwayland-scanner = {
@@ -83,9 +98,13 @@
stdenv = pkgsFor.${system}.gcc13Stdenv; stdenv = pkgsFor.${system}.gcc13Stdenv;
} { } {
name = "hyprland-shell"; name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [expat libxml2]; nativeBuildInputs = with pkgsFor.${system}; [
expat
libxml2
];
hardeningDisable = ["fortify"]; hardeningDisable = ["fortify"];
inputsFrom = [pkgsFor.${system}.hyprland]; inputsFrom = [pkgsFor.${system}.hyprland];
packages = [pkgsFor.${system}.clang-tools];
}; };
}); });

View File

@@ -5,8 +5,12 @@ project(
DESCRIPTION "Control utility for Hyprland" DESCRIPTION "Control utility for Hyprland"
) )
pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1)
add_executable(hyprctl "main.cpp") add_executable(hyprctl "main.cpp")
target_link_libraries(hyprctl PUBLIC PkgConfig::hyprctl_deps)
# binary # binary
install(TARGETS hyprctl) install(TARGETS hyprctl)

View File

@@ -38,7 +38,8 @@ commands:
plugin ... Issue a plugin request plugin ... Issue a plugin request
reload [config-only] Issue a reload to force reload the config. Pass reload [config-only] Issue a reload to force reload the config. Pass
'config-only' to disable monitor reload 'config-only' to disable monitor reload
rollinglog Prints tail of the log rollinglog Prints tail of the log. Also supports -f/--follow
option
setcursor <theme> <size> Sets the cursor theme and reloads the cursor setcursor <theme> <size> Sets the cursor theme and reloads the cursor
manager manager
seterror <color> <message...> Sets the hyprctl error string. Color has seterror <color> <message...> Sets the hyprctl error string. Color has
@@ -112,7 +113,7 @@ create <backend>:
remove <name>: remove <name>:
Removes virtual output. Pass the output's name, as found in Removes virtual output. Pass the output's name, as found in
'hyprctl monitors' 'hyprctl monitors'
flags: flags:
See 'hyprctl --help')#"; See 'hyprctl --help')#";

View File

@@ -1,13 +1,13 @@
_hyprctl_cmd_2 () { _hyprctl_cmd_2 () {
hyprctl monitors | grep Monitor | awk '{ print $2 }' hyprctl monitors | awk '/Monitor/{ print $2 }'
} }
_hyprctl_cmd_3 () { _hyprctl_cmd_3 () {
hyprpm list | grep "Plugin" | awk '{print $4}' hyprpm list | awk '/Plugin/{ print $4 }'
} }
_hyprctl_cmd_0 () { _hyprctl_cmd_0 () {
hyprctl clients | grep class | awk '{print $2}' hyprctl clients | awk '/class/{ print $2 }'
} }
_hyprctl_cmd_1 () { _hyprctl_cmd_1 () {

View File

@@ -1,16 +1,16 @@
function _hyprctl_3 function _hyprctl_3
set 1 $argv[1] set 1 $argv[1]
hyprctl monitors | grep Monitor | awk '{ print $2 }' hyprctl monitors | awk '/Monitor/{ print $2 }'
end end
function _hyprctl_4 function _hyprctl_4
set 1 $argv[1] set 1 $argv[1]
hyprpm list | grep "Plugin" | awk '{print $4}' hyprpm list | awk '/Plugin/{ print $4 }'
end end
function _hyprctl_1 function _hyprctl_1
set 1 $argv[1] set 1 $argv[1]
hyprctl clients | grep class | awk '{print $2}' hyprctl clients | awk '/class/{ print $2 }'
end end
function _hyprctl_2 function _hyprctl_2

View File

@@ -11,11 +11,11 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (-q | --quiet) "Disable output" | (-q | --quiet) "Disable output"
; ;
<WINDOWS> ::= {{{ hyprctl clients | grep class | awk '{print $2}' }}}; <WINDOWS> ::= {{{ hyprctl clients | awk '/class/{print $2}' }}};
<AVAILABLE_PLUGINS> ::= {{{ hyprpm list | grep "Plugin" | awk '{print $4}' }}}; <AVAILABLE_PLUGINS> ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}};
<MONITORS> ::= {{{ hyprctl monitors | grep Monitor | awk '{ print $2 }' }}}; <MONITORS> ::= {{{ hyprctl monitors | awk '/Monitor/{ print $2 }' }}};
<KEYBOARDS> ::= {{{ hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' }}}; <KEYBOARDS> ::= {{{ hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' }}};

View File

@@ -1,13 +1,15 @@
#compdef hyprctl
_hyprctl_cmd_2 () { _hyprctl_cmd_2 () {
hyprctl monitors | grep Monitor | awk '{ print $2 }' hyprctl monitors | awk '/Monitor/{ print $2 }'
} }
_hyprctl_cmd_3 () { _hyprctl_cmd_3 () {
hyprpm list | grep "Plugin" | awk '{print $4}' hyprpm list | awk '/Plugin/{ print $4 }'
} }
_hyprctl_cmd_0 () { _hyprctl_cmd_0 () {
hyprctl clients | grep class | awk '{print $2}' hyprctl clients | awk '/class/{ print $2 }'
} }
_hyprctl_cmd_1 () { _hyprctl_cmd_1 () {

View File

@@ -1,9 +1,9 @@
#include <ctype.h> #include <cctype>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <stdio.h> #include <cstdio>
#include <stdlib.h> #include <cstdlib>
#include <string.h> #include <cstring>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@@ -12,7 +12,7 @@
#include <unistd.h> #include <unistd.h>
#include <ranges> #include <ranges>
#include <algorithm> #include <algorithm>
#include <signal.h> #include <csignal>
#include <format> #include <format>
#include <iostream> #include <iostream>
@@ -22,8 +22,11 @@
#include <vector> #include <vector>
#include <deque> #include <deque>
#include <filesystem> #include <filesystem>
#include <stdarg.h> #include <cstdarg>
#include <regex> #include <regex>
#include <sys/socket.h>
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
#include "Strings.hpp" #include "Strings.hpp"
@@ -44,7 +47,7 @@ void log(std::string str) {
if (quiet) if (quiet)
return; return;
std::cout << str; std::cout << str << "\n";
} }
std::string getRuntimeDir() { std::string getRuntimeDir() {
@@ -98,13 +101,53 @@ std::vector<SInstanceData> instances() {
return result; return result;
} }
int request(std::string arg, int minArgs = 0) { static volatile bool sigintReceived = false;
void intHandler(int sig) {
sigintReceived = true;
std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl;
}
int rollingRead(const int socket) {
sigintReceived = false;
signal(SIGINT, intHandler);
constexpr size_t BUFFER_SIZE = 8192;
std::array<char, BUFFER_SIZE> buffer = {0};
int sizeWritten = 0;
std::cout << "[hyprctl] reading from socket following up log:" << std::endl;
while (!sigintReceived) {
sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
if (sizeWritten < 0 && errno != EAGAIN) {
if (errno != EINTR)
std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl;
close(socket);
return 5;
}
if (sizeWritten == 0)
break;
if (sizeWritten > 0) {
std::cout << std::string(buffer.data(), sizeWritten);
buffer.fill('\0');
}
usleep(100000);
}
close(socket);
return 0;
}
int request(std::string arg, int minArgs = 0, bool needRoll = false) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
auto t = timeval{.tv_sec = 5, .tv_usec = 0};
setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));
const auto ARGS = std::count(arg.begin(), arg.end(), ' '); const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
if (ARGS < minArgs) { if (ARGS < minArgs) {
log("Not enough arguments, expected at least " + minArgs); log(std::format("Not enough arguments in '{}', expected at least {}", arg, minArgs));
return -1; return -1;
} }
@@ -139,12 +182,17 @@ int request(std::string arg, int minArgs = 0) {
return 4; return 4;
} }
if (needRoll)
return rollingRead(SERVERSOCKET);
std::string reply = ""; std::string reply = "";
char buffer[8192] = {0}; char buffer[8192] = {0};
sizeWritten = read(SERVERSOCKET, buffer, 8192); sizeWritten = read(SERVERSOCKET, buffer, 8192);
if (sizeWritten < 0) { if (sizeWritten < 0) {
if (errno == EWOULDBLOCK)
log("Hyprland IPC didn't respond in time\n");
log("Couldn't read (5)"); log("Couldn't read (5)");
return 5; return 5;
} }
@@ -270,12 +318,6 @@ std::deque<std::string> splitArgs(int argc, char** argv) {
return result; return result;
} }
bool isNumber(const std::string& str, bool allowfloat) {
if (str.empty())
return false;
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
bool parseArgs = true; bool parseArgs = true;
@@ -288,6 +330,7 @@ int main(int argc, char** argv) {
std::string fullArgs = ""; std::string fullArgs = "";
const auto ARGS = splitArgs(argc, argv); const auto ARGS = splitArgs(argc, argv);
bool json = false; bool json = false;
bool needRoll = false;
std::string overrideInstance = ""; std::string overrideInstance = "";
for (std::size_t i = 0; i < ARGS.size(); ++i) { for (std::size_t i = 0; i < ARGS.size(); ++i) {
@@ -307,6 +350,9 @@ int main(int argc, char** argv) {
fullArgs += "a"; fullArgs += "a";
} else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) { } else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) {
fullArgs += "c"; fullArgs += "c";
} else if ((ARGS[i] == "-f" || ARGS[i] == "--follow") && !fullArgs.contains("f")) {
fullArgs += "f";
needRoll = true;
} else if (ARGS[i] == "--batch") { } else if (ARGS[i] == "--batch") {
fullRequest = "--batch "; fullRequest = "--batch ";
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") { } else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
@@ -366,6 +412,11 @@ int main(int argc, char** argv) {
return 0; return 0;
} }
if (needRoll && !fullRequest.contains("/rollinglog")) {
log("only 'rollinglog' command supports '--follow' option");
return 1;
}
if (overrideInstance.contains("_")) if (overrideInstance.contains("_"))
instanceSignature = overrideInstance; instanceSignature = overrideInstance;
else if (!overrideInstance.empty()) { else if (!overrideInstance.empty()) {
@@ -425,6 +476,8 @@ int main(int argc, char** argv) {
exitStatus = request(fullRequest, 1); exitStatus = request(fullRequest, 1);
else if (fullRequest.contains("/--help")) else if (fullRequest.contains("/--help"))
std::cout << USAGE << std::endl; std::cout << USAGE << std::endl;
else if (fullRequest.contains("/rollinglog") && needRoll)
exitStatus = request(fullRequest, 0, true);
else { else {
exitStatus = request(fullRequest); exitStatus = request(fullRequest);
} }

View File

@@ -1,4 +1,7 @@
executable('hyprctl', 'main.cpp', executable('hyprctl', 'main.cpp',
dependencies: [
dependency('hyprutils', version: '>= 0.1.1'),
],
install: true install: true
) )

View File

@@ -4,4 +4,4 @@ Name: Hyprland
URL: https://github.com/hyprwm/Hyprland URL: https://github.com/hyprwm/Hyprland
Description: Hyprland header files Description: Hyprland header files
Version: @HYPRLAND_VERSION@ Version: @HYPRLAND_VERSION@
Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland -I${prefix}/hyprland/wlr Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland

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(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus) pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1)
add_executable(hyprpm ${SRCFILES}) add_executable(hyprpm ${SRCFILES})
target_link_libraries(hyprpm PUBLIC PkgConfig::tomlplusplus) target_link_libraries(hyprpm PUBLIC PkgConfig::deps)
# binary # binary
install(TARGETS hyprpm) install(TARGETS hyprpm)

View File

@@ -1,5 +1,5 @@
_hyprpm_cmd_0 () { _hyprpm_cmd_0 () {
hyprpm list | grep Plugin | awk '{print $4}' hyprpm list | awk '/Plugin/{print $4}'
} }
_hyprpm () { _hyprpm () {

View File

@@ -1,6 +1,6 @@
function _hyprpm_1 function _hyprpm_1
set 1 $argv[1] set 1 $argv[1]
hyprpm list | grep Plugin | awk '{print $4}' hyprpm list | awk '/Plugin/{print $4}'
end end
function _hyprpm function _hyprpm

View File

@@ -16,4 +16,4 @@ hyprpm [<FLAGS>]... <ARGUMENT>
| (reload) "Reload all plugins" | (reload) "Reload all plugins"
; ;
<PLUGINS> ::= {{{ hyprpm list | grep Plugin | awk '{print $4}' }}}; <PLUGINS> ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}};

View File

@@ -1,7 +1,7 @@
#compdef hyprpm #compdef hyprpm
_hyprpm_cmd_0 () { _hyprpm_cmd_0 () {
hyprpm list | grep Plugin | awk '{print $4}' hyprpm list | awk '/Plugin/{print $4}'
} }
_hyprpm () { _hyprpm () {

View File

@@ -19,30 +19,15 @@
#include <toml++/toml.hpp> #include <toml++/toml.hpp>
static std::string removeBeginEndSpacesTabs(std::string str) { #include <hyprutils/string/String.hpp>
if (str.empty()) using namespace Hyprutils::String;
return str;
int countBefore = 0;
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
countBefore++;
}
int countAfter = 0;
while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
countAfter++;
}
str = str.substr(countBefore, str.length() - countBefore - countAfter);
return str;
}
static std::string execAndGet(std::string cmd) { static std::string execAndGet(std::string cmd) {
cmd += " 2>&1"; cmd += " 2>&1";
std::array<char, 128> buffer; std::array<char, 128> buffer;
std::string result; std::string result;
const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose); using PcloseType = int (*)(FILE*);
const std::unique_ptr<FILE, PcloseType> pipe(popen(cmd.c_str(), "r"), static_cast<PcloseType>(pclose));
if (!pipe) if (!pipe)
return ""; return "";
@@ -187,6 +172,9 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n"; std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n";
return false; return false;
} }
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
} }
progress.m_iSteps = 1; progress.m_iSteps = 1;
@@ -241,6 +229,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin);
ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init");
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n";
break;
} }
} }
@@ -371,10 +365,10 @@ eHeadersErrors CPluginManager::headersValid() {
else else
headers = ""; headers = "";
if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland")) if (PATH.ends_with("protocols"))
continue; continue;
verHeader = removeBeginEndSpacesTabs(PATH.substr(2)) + "/hyprland/src/version.h"; verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h";
break; break;
} }
@@ -442,12 +436,12 @@ bool CPluginManager::updateHeaders(bool force) {
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment.");
const bool bShallow = HLVER.branch == "main" || HLVER.branch == ""; const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow;
// let us give a bit of leg-room for shallowing // let us give a bit of leg-room for shallowing
// due to timezones, etc. // due to timezones, etc.
const std::string SHALLOW_DATE = const std::string SHALLOW_DATE =
removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'");
if (m_bVerbose && bShallow) if (m_bVerbose && bShallow)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE);
@@ -470,12 +464,22 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Checking out sources"; progress.m_szCurrentMessage = "Checking out sources";
progress.print(); progress.print();
ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.branch + " 2>&1"); if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1");
if (ret.contains("fatal: unable to read tree")) {
std::cerr << "\n"
<< Colors::RED << "" << Colors::RESET
<< " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n";
return false;
}
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret);
ret = execAndGet("cd " + WORKINGDIR + " && git rm subprojects/tracy && git submodule update --init 2>&1 && git reset --hard --recurse-submodules " + HLVER.hash); ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret);
@@ -495,21 +499,19 @@ bool CPluginManager::updateHeaders(bool force) {
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
if (ret.contains("required packages were not found")) { if (ret.contains("CMake Error at")) {
// missing deps, let the user know. // missing deps, let the user know.
std::string missing = ret.substr(ret.find("The following required packages were not found:")); std::string missing = ret.substr(ret.find("CMake Error at"));
missing = missing.substr(0, missing.find("Call Stack")); missing = ret.substr(ret.find_first_of('\n') + 1);
missing = missing.substr(0, missing.find("-- Configuring incomplete"));
missing = missing.substr(0, missing.find_last_of('\n')); missing = missing.substr(0, missing.find_last_of('\n'));
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" << missing << "\n"; std::cerr << "\n"
<< Colors::RED << "" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n"
<< missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n";
return false; return false;
} }
// le hack. Wlroots has to generate its build/include
ret = execAndGet("cd " + WORKINGDIR + "/subprojects/wlroots-hyprland && meson setup -Drenderers=gles2 -Dexamples=false build");
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland"); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " configured Hyprland");
progress.m_iSteps = 4; progress.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";
@@ -537,7 +539,8 @@ bool CPluginManager::updateHeaders(bool force) {
std::cout << "\n"; std::cout << "\n";
} else { } else {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID)); progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" +
headerErrorShort(HEADERSVALID) + ")");
progress.m_iSteps = 5; progress.m_iSteps = 5;
progress.m_szCurrentMessage = "Failed"; progress.m_szCurrentMessage = "Failed";
progress.print(); progress.print();
@@ -888,6 +891,18 @@ std::string CPluginManager::headerError(const eHeadersErrors err) {
return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n"; return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n";
} }
std::string CPluginManager::headerErrorShort(const eHeadersErrors err) {
switch (err) {
case HEADERS_CORRUPTED: return "Headers corrupted";
case HEADERS_MISMATCHED: return "Headers version mismatched";
case HEADERS_NOT_HYPRLAND: return "Not running on Hyprland";
case HEADERS_MISSING: return "Headers missing";
case HEADERS_DUPLICATED: return "Headers duplicated";
default: break;
}
return "?";
}
bool CPluginManager::hasDeps() { bool CPluginManager::hasDeps() {
std::vector<std::string> deps = {"meson", "cpio", "cmake"}; std::vector<std::string> deps = {"meson", "cpio", "cmake"};
for (auto& d : deps) { for (auto& d : deps) {

View File

@@ -58,13 +58,15 @@ class CPluginManager {
bool hasDeps(); bool hasDeps();
bool m_bVerbose = false; bool m_bVerbose = false;
bool m_bNoShallow = false;
// will delete recursively if exists!! // will delete recursively if exists!!
bool createSafeDirectory(const std::string& path); bool createSafeDirectory(const std::string& path);
private: private:
std::string headerError(const eHeadersErrors err); std::string headerError(const eHeadersErrors err);
std::string headerErrorShort(const eHeadersErrors err);
std::string m_szWorkingPluginDirectory = ""; std::string m_szWorkingPluginDirectory = "";
}; };

View File

@@ -26,6 +26,7 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
--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
)#"; )#";
@@ -41,7 +42,7 @@ int main(int argc, char** argv, char** envp) {
} }
std::vector<std::string> command; std::vector<std::string> command;
bool notify = false, verbose = false, force = false; bool notify = false, verbose = false, force = false, noShallow = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) { if (ARGS[i].starts_with("-")) {
@@ -52,6 +53,8 @@ int main(int argc, char** argv, char** envp) {
notify = true; notify = true;
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") { } else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
verbose = true; verbose = true;
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
noShallow = true;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") { } else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true; force = true;
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n"; std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
@@ -69,8 +72,9 @@ int main(int argc, char** argv, char** envp) {
return 0; return 0;
} }
g_pPluginManager = std::make_unique<CPluginManager>(); g_pPluginManager = std::make_unique<CPluginManager>();
g_pPluginManager->m_bVerbose = verbose; g_pPluginManager->m_bVerbose = verbose;
g_pPluginManager->m_bNoShallow = noShallow;
if (command[0] == "add") { if (command[0] == "add") {
if (command.size() < 2) { if (command.size() < 2) {

View File

@@ -3,6 +3,7 @@ src = globber.stdout().strip().split('\n')
executable('hyprpm', src, executable('hyprpm', src,
dependencies: [ dependencies: [
dependency('hyprutils', version: '>= 0.1.1'),
dependency('threads'), dependency('threads'),
dependency('tomlplusplus') dependency('tomlplusplus')
], ],

View File

@@ -1,5 +1,5 @@
project('Hyprland', 'cpp', 'c', project('Hyprland', 'cpp', 'c',
version : run_command('jq', '-r', '.version', join_paths(meson.source_root(), 'props.json'), check: true).stdout().strip(), version : run_command('cat', join_paths(meson.source_root(), 'VERSION'), check: true).stdout().strip(),
default_options : [ default_options : [
'warning_level=2', 'warning_level=2',
'default_library=static', 'default_library=static',
@@ -9,6 +9,7 @@ project('Hyprland', 'cpp', 'c',
'cpp_std=c++23', 'cpp_std=c++23',
]) ])
datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"'
add_project_arguments( add_project_arguments(
[ [
'-Wno-unused-parameter', '-Wno-unused-parameter',
@@ -16,6 +17,7 @@ add_project_arguments(
'-Wno-missing-field-initializers', '-Wno-missing-field-initializers',
'-Wno-narrowing', '-Wno-narrowing',
'-Wno-pointer-arith', '-Wno-pointer-arith',
datarootdir,
], ],
language: 'cpp') language: 'cpp')
@@ -24,8 +26,6 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif endif
wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2'])
have_xwlr = wlroots.get_variable('features').get('xwayland')
xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_dep = dependency('xcb', required: get_option('xwayland'))
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland')) xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland'))
@@ -38,12 +38,7 @@ cmake = import('cmake')
udis = cmake.subproject('udis86') udis = cmake.subproject('udis86')
udis86 = udis.dependency('libudis86') udis86 = udis.dependency('libudis86')
if get_option('xwayland').enabled() and not have_xwlr if not xcb_dep.found()
error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
endif
have_xwayland = xcb_dep.found() and have_xwlr
if not have_xwayland
add_project_arguments('-DNO_XWAYLAND', language: 'cpp') add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif endif
@@ -86,5 +81,5 @@ import('pkgconfig').generate(
url: 'https://github.com/hyprwm/Hyprland', url: 'https://github.com/hyprwm/Hyprland',
description: 'Hyprland header files', description: 'Hyprland header files',
install_dir: pkg_install_dir, install_dir: pkg_install_dir,
subdirs: ['', 'hyprland/protocols', 'hyprland', 'hyprland/wlr'], subdirs: ['', 'hyprland/protocols', 'hyprland'],
) )

View File

@@ -6,20 +6,25 @@
makeWrapper, makeWrapper,
cmake, cmake,
ninja, ninja,
aquamarine,
binutils, binutils,
cairo, cairo,
expat, expat,
fribidi, fribidi,
git, git,
hwdata,
hyprcursor, hyprcursor,
hyprlang, hyprlang,
hyprutils,
hyprwayland-scanner, hyprwayland-scanner,
jq, jq,
libGL, libGL,
libdatrie, libdatrie,
libdisplay-info,
libdrm, libdrm,
libexecinfo, libexecinfo,
libinput, libinput,
libliftoff,
libselinux, libselinux,
libsepol, libsepol,
libthai, libthai,
@@ -30,13 +35,12 @@
pciutils, pciutils,
pcre2, pcre2,
python3, python3,
seatd,
systemd, systemd,
tomlplusplus, tomlplusplus,
udis86,
wayland, wayland,
wayland-protocols, wayland-protocols,
wayland-scanner, wayland-scanner,
wlroots,
xorg, xorg,
xwayland, xwayland,
debug ? false, debug ? false,
@@ -75,23 +79,20 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
sed -i "s#@PREFIX@/##g" hyprland.pc.in sed -i "s#@PREFIX@/##g" hyprland.pc.in
''; '';
COMMITS = commit;
DATE = date; DATE = date;
DIRTY = lib.optionalString (commit == "") "dirty";
HASH = commit; HASH = commit;
DIRTY = if commit == "" then "dirty" else "";
nativeBuildInputs = lib.concatLists [ nativeBuildInputs = [
[ hyprwayland-scanner
hyprwayland-scanner jq
jq makeWrapper
makeWrapper cmake
cmake ninja
ninja pkg-config
pkg-config python3 # for udis86
python3 wayland-scanner
wayland-scanner
]
# introduce this later so that cmake takes precedence
wlroots.nativeBuildInputs
]; ];
outputs = [ outputs = [
@@ -101,19 +102,22 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
]; ];
buildInputs = lib.concatLists [ buildInputs = lib.concatLists [
wlroots.buildInputs
udis86.buildInputs
[ [
aquamarine
cairo cairo
expat expat
fribidi fribidi
git git
hyprcursor.dev hwdata
hyprcursor
hyprlang hyprlang
libGL hyprutils
libdrm
libdatrie libdatrie
libdisplay-info
libdrm
libGL
libinput libinput
libliftoff
libselinux libselinux
libsepol libsepol
libthai libthai
@@ -123,6 +127,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
pango pango
pciutils pciutils
pcre2 pcre2
seatd
tomlplusplus tomlplusplus
wayland wayland
wayland-protocols wayland-protocols
@@ -130,8 +135,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
(lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo])
(lib.optionals enableXWayland [ (lib.optionals enableXWayland [
xorg.libxcb xorg.libxcb
xorg.libXcursor
xorg.libXdmcp xorg.libXdmcp
xorg.xcbutil xorg.xcbutil
xorg.xcbutilerrors
xorg.xcbutilrenderutil
xorg.xcbutilwm xorg.xcbutilwm
xwayland xwayland
]) ])
@@ -143,6 +151,9 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
then "Debug" then "Debug"
else "RelWithDebInfo"; else "RelWithDebInfo";
# we want as much debug info as possible
dontStrip = debug;
cmakeFlags = [ cmakeFlags = [
(lib.cmakeBool "NO_XWAYLAND" (!enableXWayland)) (lib.cmakeBool "NO_XWAYLAND" (!enableXWayland))
(lib.cmakeBool "LEGACY_RENDERER" legacyRenderer) (lib.cmakeBool "LEGACY_RENDERER" legacyRenderer)
@@ -162,11 +173,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
passthru.providedSessions = ["hyprland"]; passthru.providedSessions = ["hyprland"];
meta = with lib; { meta = {
homepage = "https://github.com/hyprwm/Hyprland"; homepage = "https://github.com/hyprwm/Hyprland";
description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
license = licenses.bsd3; license = lib.licenses.bsd3;
platforms = wlroots.meta.platforms; platforms = lib.platforms.linux;
mainProgram = "Hyprland"; mainProgram = "Hyprland";
}; };
} }

View File

@@ -3,13 +3,12 @@
lib, lib,
inputs, inputs,
}: let }: let
props = builtins.fromJSON (builtins.readFile ../props.json);
mkDate = longDate: (lib.concatStringsSep "-" [ mkDate = longDate: (lib.concatStringsSep "-" [
(builtins.substring 0 4 longDate) (builtins.substring 0 4 longDate)
(builtins.substring 4 2 longDate) (builtins.substring 4 2 longDate)
(builtins.substring 6 2 longDate) (builtins.substring 6 2 longDate)
]); ]);
version = lib.removeSuffix "\n" (builtins.readFile ../VERSION);
in { in {
# Contains what a user is most likely to care about: # Contains what a user is most likely to care about:
# Hyprland itself, XDPH and the Share Picker. # Hyprland itself, XDPH and the Share Picker.
@@ -21,10 +20,11 @@ in {
# Packages for variations of Hyprland, dependencies included. # Packages for variations of Hyprland, dependencies included.
hyprland-packages = lib.composeManyExtensions [ hyprland-packages = lib.composeManyExtensions [
# Dependencies # Dependencies
inputs.aquamarine.overlays.default
inputs.hyprcursor.overlays.default inputs.hyprcursor.overlays.default
inputs.hyprlang.overlays.default inputs.hyprlang.overlays.default
inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default inputs.hyprwayland-scanner.overlays.default
self.overlays.xwayland
# Hyprland packages themselves # Hyprland packages themselves
(final: prev: let (final: prev: let
@@ -32,7 +32,7 @@ in {
in { in {
hyprland = final.callPackage ./default.nix { hyprland = final.callPackage ./default.nix {
stdenv = final.gcc13Stdenv; stdenv = final.gcc13Stdenv;
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}"; version = "${version}+date=${date}_${self.shortRev or "dirty"}";
commit = self.rev or ""; commit = self.rev or "";
inherit date; inherit date;
}; };
@@ -62,14 +62,4 @@ in {
hyprland-extras = lib.composeManyExtensions [ hyprland-extras = lib.composeManyExtensions [
inputs.xdph.overlays.xdg-desktop-portal-hyprland inputs.xdph.overlays.xdg-desktop-portal-hyprland
]; ];
# Patches XWayland's pkgconfig file to not include Cflags or includedir
# The above two variables trip up CMake and the build fails
xwayland = final: prev: {
xwayland = prev.xwayland.overrideAttrs (old: {
postInstall = ''
sed -i '/includedir/d' $out/lib/pkgconfig/xwayland.pc
'';
});
};
} }

View File

@@ -1,17 +0,0 @@
#!/usr/bin/env -S nix shell nixpkgs#gawk nixpkgs#git nixpkgs#gnused nixpkgs#ripgrep -c bash
# get wlroots revision from submodule
SUB_REV=$(git submodule status | rg wlroots | awk '{ print substr($1,2) }')
# and from lockfile
CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }')
if [ "$SUB_REV" != "$CRT_REV" ]; then
echo "Updating wlroots..."
# update wlroots to submodule revision
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix
nix flake lock
echo "wlroots: $CRT_REV -> $SUB_REV"
else
echo "wlroots is up to date!"
fi

View File

@@ -1,3 +0,0 @@
{
"version": "0.41.0"
}

View File

@@ -12,24 +12,12 @@ hyprland_protos = dependency('hyprland-protocols',
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir') hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
wayland_scanner_dep = dependency('wayland-scanner', native: true)
wayland_scanner = find_program(
wayland_scanner_dep.get_variable('wayland_scanner'),
native: true,
)
hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true) hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true)
hyprwayland_scanner = find_program( hyprwayland_scanner = find_program(
hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'),
native: true, native: true,
) )
protocols = [
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
['wlr-screencopy-unstable-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml']
]
new_protocols = [ new_protocols = [
['wlr-gamma-control-unstable-v1.xml'], ['wlr-gamma-control-unstable-v1.xml'],
['wlr-foreign-toplevel-management-unstable-v1.xml'], ['wlr-foreign-toplevel-management-unstable-v1.xml'],
@@ -42,6 +30,9 @@ new_protocols = [
['wlr-layer-shell-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'],
['wayland-drm.xml'], ['wayland-drm.xml'],
['wlr-data-control-unstable-v1.xml'], ['wlr-data-control-unstable-v1.xml'],
['wlr-screencopy-unstable-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'],
[wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
@@ -55,6 +46,7 @@ new_protocols = [
[wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'], [wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'],
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'],
[wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'], [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'],
[wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'], [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'],
@@ -66,29 +58,13 @@ new_protocols = [
[wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'],
[wl_protocol_dir, 'stable/viewporter/viewporter.xml'], [wl_protocol_dir, 'stable/viewporter/viewporter.xml'],
[wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'],
[wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'],
[wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'],
] ]
wl_protos_src = [] wl_protos_src = []
wl_protos_headers = [] wl_protos_headers = []
foreach p : protocols
xml = join_paths(p)
wl_protos_src += custom_target(
xml.underscorify() + '_server_c',
input: xml,
output: '@BASENAME@-protocol.c',
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
)
wl_protos_headers += custom_target(
xml.underscorify() + '_server_h',
input: xml,
install: true,
install_dir: join_paths(get_option('includedir'), 'hyprland/protocols'),
output: '@BASENAME@-protocol.h',
command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
)
endforeach
new_wl_protos = [] new_wl_protos = []
foreach p : new_protocols foreach p : new_protocols
xml = join_paths(p) xml = join_paths(p)
@@ -113,7 +89,8 @@ foreach p : wl_server_protos
wl_server_protos_gen += custom_target( wl_server_protos_gen += custom_target(
p.underscorify(), p.underscorify(),
input: p, input: p,
install: false, install: true,
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'], command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'],
) )

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include <deque> #include <deque>
#include <list> #include <list>
#include <sys/resource.h>
#include "defines.hpp" #include "defines.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
@@ -29,6 +30,9 @@
#include "plugins/PluginSystem.hpp" #include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp" #include "helpers/Watchdog.hpp"
#include <aquamarine/backend/Backend.hpp>
#include <aquamarine/output/Output.hpp>
class CWLSurfaceResource; class CWLSurfaceResource;
enum eManagersInitStage { enum eManagersInitStage {
@@ -42,22 +46,11 @@ class CCompositor {
CCompositor(); CCompositor();
~CCompositor(); ~CCompositor();
// ------------------ WLR BASICS ------------------ // wl_display* m_sWLDisplay;
wl_display* m_sWLDisplay; wl_event_loop* m_sWLEventLoop;
wl_event_loop* m_sWLEventLoop; int m_iDRMFD = -1;
wlr_backend* m_sWLRBackend; bool m_bInitialized = false;
wlr_session* m_sWLRSession; SP<Aquamarine::CBackend> m_pAqBackend;
wlr_renderer* m_sWLRRenderer;
wlr_allocator* m_sWLRAllocator;
wlr_compositor* m_sWLRCompositor;
wlr_subcompositor* m_sWLRSubCompositor;
wlr_drm* m_sWRLDRM;
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_egl* m_sWLREGL;
int m_iDRMFD;
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
wlr_backend* m_sWLRHeadlessBackend;
// ------------------------------------------------- //
std::string m_szHyprTempDataRoot = ""; std::string m_szHyprTempDataRoot = "";
@@ -76,11 +69,14 @@ class CCompositor {
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap; std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;
void initServer(); void initServer(std::string socketName, int socketFd);
void startCompositor(); void startCompositor();
void stopCompositor();
void cleanup(); void cleanup();
void createLockFile(); void createLockFile();
void removeLockFile(); void removeLockFile();
void bumpNofile();
void restoreNofile();
WP<CWLSurfaceResource> m_pLastFocus; WP<CWLSurfaceResource> m_pLastFocus;
PHLWINDOWREF m_pLastWindow; PHLWINDOWREF m_pLastWindow;
@@ -91,10 +87,9 @@ class CCompositor {
bool m_bReadyToProcess = false; bool m_bReadyToProcess = false;
bool m_bSessionActive = true; bool m_bSessionActive = true;
bool m_bDPMSStateON = true; bool m_bDPMSStateON = true;
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; // because wlroots bool m_bNextIsUnsafe = false;
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bExitTriggered = false; // For exit dispatcher
bool m_bIsShuttingDown = false; bool m_bIsShuttingDown = false;
// ------------------------------------------------- // // ------------------------------------------------- //
@@ -113,17 +108,18 @@ class CCompositor {
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* 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>);
CMonitor* getMonitorFromOutput(wlr_output*); CMonitor* getMonitorFromOutput(SP<Aquamarine::IOutput>);
CMonitor* getRealMonitorFromOutput(wlr_output*); CMonitor* getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>); PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
PHLWINDOW getWindowFromHandle(uint32_t); PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE); bool isWorkspaceVisible(PHLWORKSPACE);
bool isWorkspaceVisibleNotCovered(PHLWORKSPACE);
PHLWORKSPACE getWorkspaceByID(const int&); PHLWORKSPACE getWorkspaceByID(const int&);
PHLWORKSPACE getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByName(const std::string&);
PHLWORKSPACE getWorkspaceByString(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces(); void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&); void updateWorkspaceWindowDecos(const int&);
void updateWorkspaceSpecialRenderData(const int&); void updateWorkspaceWindowData(const int&);
int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {}); int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {}); int getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
PHLWINDOW getUrgentWindow(); PHLWINDOW getUrgentWindow();
@@ -150,11 +146,16 @@ class CCompositor {
void swapActiveWorkspaces(CMonitor*, CMonitor*); void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&); CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&); bool workspaceIDOutOfBounds(const int64_t&);
void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state);
void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW); PHLWINDOW getX11Parent(PHLWINDOW);
void scheduleFrameForMonitor(CMonitor*); void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
void addToFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLLS);
void removeFromFadingOutSafe(PHLLS);
void addToFadingOutSafe(PHLWINDOW); void addToFadingOutSafe(PHLWINDOW);
PHLWINDOW getWindowByRegex(const std::string&); PHLWINDOW getWindowByRegex(const std::string&);
void warpCursorTo(const Vector2D&, bool force = false); void warpCursorTo(const Vector2D&, bool force = false);
@@ -177,6 +178,7 @@ class CCompositor {
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform); void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates(); void updateSuspendedStates();
PHLWINDOW windowForCPointer(CWindow*); PHLWINDOW windowForCPointer(CWindow*);
void onNewMonitor(SP<Aquamarine::IOutput> output);
std::string explicitConfigPath; std::string explicitConfigPath;
@@ -188,8 +190,9 @@ class CCompositor {
void initManagers(eManagersInitStage stage); void initManagers(eManagersInitStage stage);
void prepareFallbackOutput(); void prepareFallbackOutput();
uint64_t m_iHyprlandPID = 0; uint64_t m_iHyprlandPID = 0;
wl_event_source* m_critSigSource = nullptr; wl_event_source* m_critSigSource = nullptr;
rlimit m_sOriginalNofile = {0};
}; };
inline std::unique_ptr<CCompositor> g_pCompositor; inline std::unique_ptr<CCompositor> g_pCompositor;

View File

@@ -1,7 +1,11 @@
#pragma once #pragma once
#include "helpers/Vector2D.hpp" #include "helpers/math/Math.hpp"
#include <functional> #include <functional>
#include <any>
#include <hyprutils/math/Box.hpp>
using namespace Hyprutils::Math;
enum eIcons { enum eIcons {
ICON_WARNING = 0, ICON_WARNING = 0,
@@ -37,29 +41,6 @@ struct SCallbackInfo {
bool cancelled = false; /* on cancellable events, will cancel the event. */ bool cancelled = false; /* on cancellable events, will cancel the event. */
}; };
struct SWindowDecorationExtents {
Vector2D topLeft;
Vector2D bottomRight;
//
SWindowDecorationExtents operator*(const double& scale) const {
return SWindowDecorationExtents{topLeft * scale, bottomRight * scale};
}
SWindowDecorationExtents round() {
return {topLeft.round(), bottomRight.round()};
}
bool operator==(const SWindowDecorationExtents& other) const {
return topLeft == other.topLeft && bottomRight == other.bottomRight;
}
void addExtents(const SWindowDecorationExtents& other) {
topLeft = topLeft.getComponentMax(other.topLeft);
bottomRight = bottomRight.getComponentMax(other.bottomRight);
}
};
enum eHyprCtlOutputFormat { enum eHyprCtlOutputFormat {
FORMAT_NORMAL = 0, FORMAT_NORMAL = 0,
FORMAT_JSON FORMAT_JSON

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/VarList.hpp" #include "../helpers/varlist/VarList.hpp"
#include <vector> #include <vector>
enum eConfigValueDataTypes { enum eConfigValueDataTypes {
@@ -20,11 +20,11 @@ class ICustomConfigValueData {
class CGradientValueData : public ICustomConfigValueData { class CGradientValueData : public ICustomConfigValueData {
public: public:
CGradientValueData(){}; CGradientValueData() {};
CGradientValueData(CColor col) { CGradientValueData(CColor col) {
m_vColors.push_back(col); m_vColors.push_back(col);
}; };
virtual ~CGradientValueData(){}; virtual ~CGradientValueData() {};
virtual eConfigValueDataTypes getDataType() { virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_GRADIENT; return CVD_TYPE_GRADIENT;
@@ -67,11 +67,11 @@ class CGradientValueData : public ICustomConfigValueData {
class CCssGapData : public ICustomConfigValueData { class CCssGapData : public ICustomConfigValueData {
public: public:
CCssGapData() : top(0), right(0), bottom(0), left(0){}; CCssGapData() : top(0), right(0), bottom(0), left(0) {};
CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global){}; CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global) {};
CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal){}; CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), 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) : top(top), right(horizontal), bottom(bottom), 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) : top(top), right(right), bottom(bottom), left(left) {};
/* Css like directions */ /* Css like directions */
int64_t top; int64_t top;

View File

@@ -3,16 +3,20 @@
#include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "config/ConfigDataValues.hpp" #include "config/ConfigDataValues.hpp"
#include "helpers/VarList.hpp" #include "config/ConfigValue.hpp"
#include "helpers/varlist/VarList.hpp"
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <hyprutils/path/Path.hpp>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <glob.h> #include <glob.h>
#include <xkbcommon/xkbcommon.h>
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
@@ -20,7 +24,9 @@
#include <sstream> #include <sstream>
#include <ranges> #include <ranges>
#include <unordered_set> #include <unordered_set>
#include <xkbcommon/xkbcommon.h> #include <hyprutils/string/String.hpp>
#include <filesystem>
using namespace Hyprutils::String;
extern "C" char** environ; extern "C" char** environ;
@@ -341,7 +347,6 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("misc:swallow_regex", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:swallow_regex", {STRVAL_EMPTY});
m_pConfig->addConfigValue("misc:swallow_exception_regex", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:swallow_exception_regex", {STRVAL_EMPTY});
m_pConfig->addConfigValue("misc:focus_on_activate", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:focus_on_activate", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:no_direct_scanout", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:mouse_move_focuses_monitor", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:mouse_move_focuses_monitor", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:render_ahead_of_time", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:render_ahead_of_time", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:render_ahead_safezone", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:render_ahead_safezone", Hyprlang::INT{1});
@@ -349,6 +354,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("misc:close_special_on_empty", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:close_special_on_empty", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:background_color", Hyprlang::INT{0xff111111}); m_pConfig->addConfigValue("misc:background_color", Hyprlang::INT{0xff111111});
m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:exit_window_retains_fullscreen", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1});
@@ -428,8 +434,9 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("master:special_scale_factor", {1.f}); m_pConfig->addConfigValue("master:special_scale_factor", {1.f});
m_pConfig->addConfigValue("master:mfact", {0.55f}); m_pConfig->addConfigValue("master:mfact", {0.55f});
m_pConfig->addConfigValue("master:new_is_master", Hyprlang::INT{1}); m_pConfig->addConfigValue("master:new_status", {"slave"});
m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0});
m_pConfig->addConfigValue("master:new_on_active", {"none"});
m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0});
m_pConfig->addConfigValue("master:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:no_gaps_when_only", Hyprlang::INT{0});
m_pConfig->addConfigValue("master:orientation", {"left"}); m_pConfig->addConfigValue("master:orientation", {"left"});
@@ -466,6 +473,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("input:scroll_button_lock", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:scroll_button_lock", Hyprlang::INT{0});
m_pConfig->addConfigValue("input:scroll_factor", {1.f}); m_pConfig->addConfigValue("input:scroll_factor", {1.f});
m_pConfig->addConfigValue("input:scroll_points", {STRVAL_EMPTY}); m_pConfig->addConfigValue("input:scroll_points", {STRVAL_EMPTY});
m_pConfig->addConfigValue("input:emulate_discrete_scroll", Hyprlang::INT{1});
m_pConfig->addConfigValue("input:touchpad:natural_scroll", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:touchpad:natural_scroll", Hyprlang::INT{0});
m_pConfig->addConfigValue("input:touchpad:disable_while_typing", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:touchpad:disable_while_typing", Hyprlang::INT{1});
m_pConfig->addConfigValue("input:touchpad:clickfinger_behavior", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:touchpad:clickfinger_behavior", Hyprlang::INT{0});
@@ -511,6 +519,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("gestures:workspace_swipe_forever", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_forever", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_use_r", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_use_r", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_touch", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_touch", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_touch_invert", Hyprlang::INT{0});
m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1}); m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1});
m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0}); m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0});
@@ -519,16 +528,20 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2}); m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2});
m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24});
m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:warp_on_change_workspace", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:default_monitor", {STRVAL_EMPTY}); m_pConfig->addConfigValue("cursor:default_monitor", {STRVAL_EMPTY});
m_pConfig->addConfigValue("cursor:zoom_factor", {1.f}); m_pConfig->addConfigValue("cursor:zoom_factor", {1.f});
m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1});
m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1});
m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0});
m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0});
@@ -547,6 +560,10 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"});
m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"});
m_pConfig->addConfigValue("render:explicit_sync", Hyprlang::INT{2});
m_pConfig->addConfigValue("render:explicit_sync_kms", Hyprlang::INT{2});
m_pConfig->addConfigValue("render:direct_scanout", Hyprlang::INT{0});
// devices // devices
m_pConfig->addSpecialCategory("device", {"name"}); m_pConfig->addSpecialCategory("device", {"name"});
m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F}); m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F});
@@ -620,20 +637,49 @@ CConfigManager::CConfigManager() {
g_pHyprError->queueCreate(ERR.value(), CColor{1.0, 0.1, 0.1, 1.0}); g_pHyprError->queueCreate(ERR.value(), CColor{1.0, 0.1, 0.1, 1.0});
} }
std::string CConfigManager::getConfigDir() { std::optional<std::string> CConfigManager::generateConfig(std::string configPath) {
static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME"); std::string parentPath = std::filesystem::path(configPath).parent_path();
if (xdgConfigHome && std::filesystem::path(xdgConfigHome).is_absolute()) if (!std::filesystem::is_directory(parentPath)) {
return xdgConfigHome; Debug::log(WARN, "Creating config home directory");
try {
std::filesystem::create_directories(parentPath);
} catch (std::exception& e) { throw e; }
}
return getenv("HOME") + std::string("/.config"); Debug::log(WARN, "No config file found; attempting to generate.");
std::ofstream ofs;
ofs.open(configPath, std::ios::trunc);
ofs << AUTOCONFIG;
ofs.close();
if (!std::filesystem::exists(configPath))
return "Config could not be generated.";
return configPath;
} }
std::string CConfigManager::getMainConfigPath() { std::string CConfigManager::getMainConfigPath() {
if (!g_pCompositor->explicitConfigPath.empty()) if (!g_pCompositor->explicitConfigPath.empty())
return g_pCompositor->explicitConfigPath; return g_pCompositor->explicitConfigPath;
return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf"); static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland");
if (paths.first.has_value()) {
return paths.first.value();
} else if (paths.second.has_value()) {
auto configPath = Hyprutils::Path::fullConfigPath(paths.second.value(), ISDEBUG ? "hyprlandd" : "hyprland");
return generateConfig(configPath).value();
} else
throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME are set in the environment. Could not find config in XDG_CONFIG_DIRS or /etc/xdg.");
}
std::optional<std::string> CConfigManager::verifyConfigExists() {
std::string mainConfigPath = getMainConfigPath();
if (!std::filesystem::exists(mainConfigPath))
return "broken config dir?";
return {};
} }
const std::string CConfigManager::getConfigString() { const std::string CConfigManager::getConfigString() {
@@ -729,32 +775,6 @@ void CConfigManager::setDefaultAnimationVars() {
CREATEANIMCFG("specialWorkspace", "workspaces"); CREATEANIMCFG("specialWorkspace", "workspaces");
} }
std::optional<std::string> CConfigManager::verifyConfigExists() {
std::string mainConfigPath = getMainConfigPath();
if (g_pCompositor->explicitConfigPath.empty() && !std::filesystem::exists(mainConfigPath)) {
std::string configPath = std::filesystem::path(mainConfigPath).parent_path();
if (!std::filesystem::is_directory(configPath)) {
Debug::log(WARN, "Creating config home directory");
try {
std::filesystem::create_directories(configPath);
} catch (...) { return "Broken config file! (Could not create config directory)"; }
}
Debug::log(WARN, "No config file found; attempting to generate.");
std::ofstream ofs;
ofs.open(mainConfigPath, std::ios::trunc);
ofs << AUTOCONFIG;
ofs.close();
}
if (!std::filesystem::exists(mainConfigPath))
return "broken config dir?";
return {};
}
std::optional<std::string> CConfigManager::resetHLConfig() { std::optional<std::string> CConfigManager::resetHLConfig() {
m_dMonitorRules.clear(); m_dMonitorRules.clear();
m_dWindowRules.clear(); m_dWindowRules.clear();
@@ -780,6 +800,9 @@ std::optional<std::string> CConfigManager::resetHLConfig() {
} }
void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync");
static int prevEnabledExplicit = *PENABLEEXPLICIT;
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
w->uncacheWindowDecos(); w->uncacheWindowDecos();
} }
@@ -798,6 +821,9 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
if (!isFirstLaunch) if (!isFirstLaunch)
g_pHyprOpenGL->m_bReloadScreenShader = true; g_pHyprOpenGL->m_bReloadScreenShader = true;
if (!isFirstLaunch && *PENABLEEXPLICIT != prevEnabledExplicit)
g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
// parseError will be displayed next frame // parseError will be displayed next frame
if (result.error) if (result.error)
@@ -832,7 +858,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
if (w->inert()) if (w->inert())
continue; continue;
g_pCompositor->updateWorkspaceWindows(w->m_iID); g_pCompositor->updateWorkspaceWindows(w->m_iID);
g_pCompositor->updateWorkspaceSpecialRenderData(w->m_iID); g_pCompositor->updateWorkspaceWindowData(w->m_iID);
} }
// Update window border colors // Update window border colors
@@ -975,7 +1001,8 @@ float CConfigManager::getDeviceFloat(const std::string& dev, const std::string&
} }
Vector2D CConfigManager::getDeviceVec(const std::string& dev, const std::string& v, const std::string& fallback) { Vector2D CConfigManager::getDeviceVec(const std::string& dev, const std::string& v, const std::string& fallback) {
return std::any_cast<Hyprlang::VEC2>(getConfigValueSafeDevice(dev, v, fallback)->getValue()); auto vec = std::any_cast<Hyprlang::VEC2>(getConfigValueSafeDevice(dev, v, fallback)->getValue());
return {vec.x, vec.y};
} }
std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v, const std::string& fallback) { std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v, const std::string& fallback) {
@@ -1045,14 +1072,14 @@ SWorkspaceRule CConfigManager::mergeWorkspaceRules(const SWorkspaceRule& rule1,
mergedRule.gapsOut = rule2.gapsOut; mergedRule.gapsOut = rule2.gapsOut;
if (rule2.borderSize.has_value()) if (rule2.borderSize.has_value())
mergedRule.borderSize = rule2.borderSize; mergedRule.borderSize = rule2.borderSize;
if (rule2.border.has_value()) if (rule2.noBorder.has_value())
mergedRule.border = rule2.border; mergedRule.noBorder = rule2.noBorder;
if (rule2.rounding.has_value()) if (rule2.noRounding.has_value())
mergedRule.rounding = rule2.rounding; mergedRule.noRounding = rule2.noRounding;
if (rule2.decorate.has_value()) if (rule2.decorate.has_value())
mergedRule.decorate = rule2.decorate; mergedRule.decorate = rule2.decorate;
if (rule2.shadow.has_value()) if (rule2.noShadow.has_value())
mergedRule.shadow = rule2.shadow; mergedRule.noShadow = rule2.noShadow;
if (rule2.onCreatedEmptyRunCmd.has_value()) if (rule2.onCreatedEmptyRunCmd.has_value())
mergedRule.onCreatedEmptyRunCmd = rule2.onCreatedEmptyRunCmd; mergedRule.onCreatedEmptyRunCmd = rule2.onCreatedEmptyRunCmd;
if (rule2.defaultName.has_value()) if (rule2.defaultName.has_value())
@@ -1081,7 +1108,7 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo
// since some rules will be applied later, we need to store some flags // since some rules will be applied later, we need to store some flags
bool hasFloating = pWindow->m_bIsFloating; bool hasFloating = pWindow->m_bIsFloating;
bool hasFullscreen = pWindow->m_bIsFullscreen; bool hasFullscreen = pWindow->isFullscreen();
// local tags for dynamic tag rule match // local tags for dynamic tag rule match
auto tags = pWindow->m_tags; auto tags = pWindow->m_tags;
@@ -1271,21 +1298,23 @@ void CConfigManager::dispatchExecOnce() {
return; return;
// update dbus env // update dbus env
if (g_pCompositor->m_sWLRSession) if (g_pCompositor->m_pAqBackend->hasSession())
handleRawExec("", handleRawExec("",
#ifdef USES_SYSTEMD #ifdef USES_SYSTEMD
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME && hash " "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
"dbus-update-activation-environment 2>/dev/null && " "dbus-update-activation-environment 2>/dev/null && "
#endif #endif
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME"); "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS");
firstExecDispatched = true; firstExecDispatched = true;
isLaunchingExecOnce = true;
for (auto& c : firstExecRequests) { for (auto& c : firstExecRequests) {
handleRawExec("", c); handleRawExec("", c);
} }
firstExecRequests.clear(); // free some kb of memory :P firstExecRequests.clear(); // free some kb of memory :P
isLaunchingExecOnce = false;
// set input, fixes some certain issues // set input, fixes some certain issues
g_pInputManager->setKeyboardLayout(); g_pInputManager->setKeyboardLayout();
@@ -1396,7 +1425,8 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
if (USEVRR == 0) { if (USEVRR == 0) {
if (m->vrrActive) { if (m->vrrActive) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(false);
if (!m->state.commit()) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
@@ -1405,11 +1435,12 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
return; return;
} else if (USEVRR == 1) { } else if (USEVRR == 1) {
if (!m->vrrActive) { if (!m->vrrActive) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1); m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(true);
if (!m->state.test()) { if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); m->output->state->setAdaptiveSync(false);
} }
if (!m->state.commit()) if (!m->state.commit())
@@ -1426,21 +1457,23 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
if (!PWORKSPACE) if (!PWORKSPACE)
return; // ??? return; // ???
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN);
if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) { if (WORKSPACEFULL) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1); m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(true);
if (!m->state.test()) { if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); m->output->state->setAdaptiveSync(false);
} }
if (!m->state.commit()) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) { } else if (!WORKSPACEFULL) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(false);
if (!m->state.commit()) if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
@@ -1807,14 +1840,13 @@ std::optional<std::string> CConfigManager::handleMonitor(const std::string& comm
newrule.vrr = std::stoi(ARGS[argno + 1]); newrule.vrr = std::stoi(ARGS[argno + 1]);
argno++; argno++;
} else if (ARGS[argno] == "workspace") { } else if (ARGS[argno] == "workspace") {
std::string name = ""; const auto& [id, name] = getWorkspaceIDNameFromString(ARGS[argno + 1]);
int wsId = getWorkspaceIDFromString(ARGS[argno + 1], name);
SWorkspaceRule wsRule; SWorkspaceRule wsRule;
wsRule.monitor = newrule.name; wsRule.monitor = newrule.name;
wsRule.workspaceString = ARGS[argno + 1]; wsRule.workspaceString = ARGS[argno + 1];
wsRule.workspaceId = id;
wsRule.workspaceName = name; wsRule.workspaceName = name;
wsRule.workspaceId = wsId;
m_dWorkspaceRules.emplace_back(wsRule); m_dWorkspaceRules.emplace_back(wsRule);
argno++; argno++;
@@ -1955,15 +1987,17 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
// bind[fl]=SUPER,G,exec,dmenu_run <args> // bind[fl]=SUPER,G,exec,dmenu_run <args>
// flags // flags
bool locked = false; bool locked = false;
bool release = false; bool release = false;
bool repeat = false; bool repeat = false;
bool mouse = false; bool mouse = false;
bool nonConsuming = false; bool nonConsuming = false;
bool transparent = false; bool transparent = false;
bool ignoreMods = false; bool ignoreMods = false;
bool multiKey = false; bool multiKey = false;
const auto BINDARGS = command.substr(4); bool hasDescription = false;
bool dontInhibit = false;
const auto BINDARGS = command.substr(4);
for (auto& arg : BINDARGS) { for (auto& arg : BINDARGS) {
if (arg == 'l') { if (arg == 'l') {
@@ -1982,6 +2016,10 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
ignoreMods = true; ignoreMods = true;
} else if (arg == 's') { } else if (arg == 's') {
multiKey = true; multiKey = true;
} else if (arg == 'd') {
hasDescription = true;
} else if (arg == 'p') {
dontInhibit = true;
} else { } else {
return "bind: invalid flag"; return "bind: invalid flag";
} }
@@ -1993,11 +2031,13 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
if (mouse && (repeat || release || locked)) if (mouse && (repeat || release || locked))
return "flag m is exclusive"; return "flag m is exclusive";
const auto ARGS = CVarList(value, 4); const int numbArgs = hasDescription ? 5 : 4;
const auto ARGS = CVarList(value, numbArgs);
const int DESCR_OFFSET = hasDescription ? 1 : 0;
if ((ARGS.size() < 3 && !mouse) || (ARGS.size() < 3 && mouse)) if ((ARGS.size() < 3 && !mouse) || (ARGS.size() < 3 && mouse))
return "bind: too few args"; return "bind: too few args";
else if ((ARGS.size() > 4 && !mouse) || (ARGS.size() > 3 && mouse)) else if ((ARGS.size() > (size_t)4 + DESCR_OFFSET && !mouse) || (ARGS.size() > (size_t)3 + DESCR_OFFSET && mouse))
return "bind: too many args"; return "bind: too many args";
std::set<xkb_keysym_t> KEYSYMS; std::set<xkb_keysym_t> KEYSYMS;
@@ -2016,9 +2056,11 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
const auto KEY = multiKey ? "" : ARGS[1]; const auto KEY = multiKey ? "" : ARGS[1];
auto HANDLER = ARGS[2]; const auto DESCRIPTION = hasDescription ? ARGS[2] : "";
const auto COMMAND = mouse ? HANDLER : ARGS[3]; auto HANDLER = ARGS[2 + DESCR_OFFSET];
const auto COMMAND = mouse ? HANDLER : ARGS[3 + DESCR_OFFSET];
if (mouse) if (mouse)
HANDLER = "mouse"; HANDLER = "mouse";
@@ -2046,8 +2088,9 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
return "Invalid catchall, catchall keybinds are only allowed in submaps."; return "Invalid catchall, catchall keybinds are only allowed in submaps.";
} }
g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, g_pKeybindManager->addKeybind(SKeybind{
repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey}); parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, release,
repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription, dontInhibit});
} }
return {}; return {};
@@ -2067,16 +2110,17 @@ std::optional<std::string> CConfigManager::handleUnbind(const std::string& comma
bool windowRuleValid(const std::string& RULE) { bool windowRuleValid(const std::string& RULE) {
static const auto rules = std::unordered_set<std::string>{ static const auto rules = std::unordered_set<std::string>{
"dimaround", "fakefullscreen", "float", "focusonactivate", "forceinput", "forcergbx", "fullscreen", "immediate", "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile",
"keepaspectratio", "maximize", "nearestneighbor", "noanim", "noblur", "noborder", "nodim", "nofocus",
"noinitialfocus", "nomaxsize", "noshadow", "opaque", "pin", "stayfocused", "tile", "windowdance",
}; };
static const auto rulesPrefix = std::vector<std::string>{ static const auto rulesPrefix = std::vector<std::string>{
"animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor",
"opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray", "move", "opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray",
}; };
return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }); const auto VALS = CVarList(RULE, 2, ' ');
return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }) ||
(g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) ||
(g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end());
} }
bool layerRuleValid(const std::string& RULE) { bool layerRuleValid(const std::string& RULE) {
@@ -2087,8 +2131,8 @@ bool layerRuleValid(const std::string& RULE) {
} }
std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) { std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(','))); const auto RULE = trim(value.substr(0, value.find_first_of(',')));
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1)); const auto VALUE = trim(value.substr(value.find_first_of(',') + 1));
// check rule and value // check rule and value
if (RULE.empty() || VALUE.empty()) if (RULE.empty() || VALUE.empty())
@@ -2114,8 +2158,8 @@ std::optional<std::string> CConfigManager::handleWindowRule(const std::string& c
} }
std::optional<std::string> CConfigManager::handleLayerRule(const std::string& command, const std::string& value) { std::optional<std::string> CConfigManager::handleLayerRule(const std::string& command, const std::string& value) {
const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(','))); const auto RULE = trim(value.substr(0, value.find_first_of(',')));
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1)); const auto VALUE = trim(value.substr(value.find_first_of(',') + 1));
// check rule and value // check rule and value
if (RULE.empty() || VALUE.empty()) if (RULE.empty() || VALUE.empty())
@@ -2142,7 +2186,7 @@ std::optional<std::string> CConfigManager::handleLayerRule(const std::string& co
} }
std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) { std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) {
const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(','))); const auto RULE = trim(value.substr(0, value.find_first_of(',')));
const auto VALUE = value.substr(value.find_first_of(',') + 1); const auto VALUE = value.substr(value.find_first_of(',') + 1);
if (!windowRuleValid(RULE) && RULE != "unset") { if (!windowRuleValid(RULE) && RULE != "unset") {
@@ -2219,7 +2263,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
result = result.substr(0, min - pos); result = result.substr(0, min - pos);
result = removeBeginEndSpacesTabs(result); result = trim(result);
if (!result.empty() && result.back() == ',') if (!result.empty() && result.back() == ',')
result.pop_back(); result.pop_back();
@@ -2341,7 +2385,7 @@ void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBl
std::optional<std::string> CConfigManager::handleBlurLS(const std::string& command, const std::string& value) { std::optional<std::string> CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
if (value.starts_with("remove,")) { if (value.starts_with("remove,")) {
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7)); const auto TOREMOVE = trim(value.substr(7));
if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; })) if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; }))
updateBlurredLS(TOREMOVE, false); updateBlurredLS(TOREMOVE, false);
return {}; return {};
@@ -2355,11 +2399,11 @@ std::optional<std::string> CConfigManager::handleBlurLS(const std::string& comma
std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::string& command, const std::string& value) { std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::string& command, const std::string& value) {
// This can either be the monitor or the workspace identifier // This can either be the monitor or the workspace identifier
const auto FIRST_DELIM = value.find_first_of(','); const auto FIRST_DELIM = value.find_first_of(',');
std::string name = ""; auto first_ident = trim(value.substr(0, FIRST_DELIM));
auto first_ident = removeBeginEndSpacesTabs(value.substr(0, FIRST_DELIM));
int id = getWorkspaceIDFromString(first_ident, name); const auto& [id, name] = getWorkspaceIDNameFromString(first_ident);
auto rules = value.substr(FIRST_DELIM + 1); auto rules = value.substr(FIRST_DELIM + 1);
SWorkspaceRule wsRule; SWorkspaceRule wsRule;
@@ -2402,11 +2446,11 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
wsRule.borderSize = std::stoi(rule.substr(delim + 11)); wsRule.borderSize = std::stoi(rule.substr(delim + 11));
} catch (...) { return "Error parsing workspace rule bordersize: {}", rule.substr(delim + 11); } } catch (...) { return "Error parsing workspace rule bordersize: {}", rule.substr(delim + 11); }
else if ((delim = rule.find("border:")) != std::string::npos) else if ((delim = rule.find("border:")) != std::string::npos)
wsRule.border = configStringToInt(rule.substr(delim + 7)); wsRule.noBorder = !configStringToInt(rule.substr(delim + 7));
else if ((delim = rule.find("shadow:")) != std::string::npos) else if ((delim = rule.find("shadow:")) != std::string::npos)
wsRule.shadow = configStringToInt(rule.substr(delim + 7)); wsRule.noShadow = !configStringToInt(rule.substr(delim + 7));
else if ((delim = rule.find("rounding:")) != std::string::npos) else if ((delim = rule.find("rounding:")) != std::string::npos)
wsRule.rounding = configStringToInt(rule.substr(delim + 9)); wsRule.noRounding = !configStringToInt(rule.substr(delim + 9));
else if ((delim = rule.find("decorate:")) != std::string::npos) else if ((delim = rule.find("decorate:")) != std::string::npos)
wsRule.decorate = configStringToInt(rule.substr(delim + 9)); wsRule.decorate = configStringToInt(rule.substr(delim + 9));
else if ((delim = rule.find("monitor:")) != std::string::npos) else if ((delim = rule.find("monitor:")) != std::string::npos)

View File

@@ -15,7 +15,7 @@
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include "../helpers/WLClasses.hpp" #include "../helpers/WLClasses.hpp"
#include "../helpers/Monitor.hpp" #include "../helpers/Monitor.hpp"
#include "../helpers/VarList.hpp" #include "../helpers/varlist/VarList.hpp"
#include "../desktop/Window.hpp" #include "../desktop/Window.hpp"
#include "../desktop/LayerSurface.hpp" #include "../desktop/LayerSurface.hpp"
@@ -39,10 +39,10 @@ struct SWorkspaceRule {
std::optional<CCssGapData> gapsIn; std::optional<CCssGapData> gapsIn;
std::optional<CCssGapData> gapsOut; std::optional<CCssGapData> gapsOut;
std::optional<int64_t> borderSize; std::optional<int64_t> borderSize;
std::optional<int> border; std::optional<bool> decorate;
std::optional<int> rounding; std::optional<bool> noRounding;
std::optional<int> decorate; std::optional<bool> noBorder;
std::optional<int> shadow; std::optional<bool> noShadow;
std::optional<std::string> onCreatedEmptyRunCmd; std::optional<std::string> onCreatedEmptyRunCmd;
std::optional<std::string> defaultName; std::optional<std::string> defaultName;
std::map<std::string, std::string> layoutopts; std::map<std::string, std::string> layoutopts;
@@ -101,7 +101,6 @@ class CConfigManager {
void* const* getConfigValuePtr(const std::string&); void* const* getConfigValuePtr(const std::string&);
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = ""); Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load); void onPluginLoadUnload(const std::string& name, bool load);
static std::string getConfigDir();
static std::string getMainConfigPath(); static std::string getMainConfigPath();
const std::string getConfigString(); const std::string getConfigString();
@@ -130,9 +129,6 @@ class CConfigManager {
void performMonitorReload(); void performMonitorReload();
void appendMonitorRule(const SMonitorRule&); void appendMonitorRule(const SMonitorRule&);
bool replaceMonitorRule(const SMonitorRule&); bool replaceMonitorRule(const SMonitorRule&);
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
void ensureMonitorStatus(); void ensureMonitorStatus();
void ensureVRR(CMonitor* pMonitor = nullptr); void ensureVRR(CMonitor* pMonitor = nullptr);
@@ -148,25 +144,56 @@ class CConfigManager {
std::string getErrors(); std::string getErrors();
// keywords // keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&); std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&); std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&); std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&); std::optional<std::string> handleBind(const std::string&, const std::string&);
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> 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&);
std::optional<std::string> handleSource(const std::string&, const std::string&); std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&); std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&); std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&); std::optional<std::string> 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::string configCurrentPath; std::string configCurrentPath;
std::unordered_map<std::string, std::function<CWindowOverridableVar<bool>*(PHLWINDOW)>> mbWindowProperties = {
{"allowsinput", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.allowsInput; }},
{"dimaround", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.dimAround; }},
{"decorate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.decorate; }},
{"focusonactivate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }},
{"keepaspectratio", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }},
{"nearestneighbor", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }},
{"noanim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noAnim; }},
{"noblur", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBlur; }},
{"noborder", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBorder; }},
{"nodim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noDim; }},
{"nofocus", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noFocus; }},
{"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }},
{"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }},
{"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }},
{"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }},
{"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }},
{"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }},
{"syncfullscreen", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }},
{"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }},
{"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }},
};
std::unordered_map<std::string, std::function<CWindowOverridableVar<int>*(PHLWINDOW)>> miWindowProperties = {
{"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}};
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking
private: private:
std::unique_ptr<Hyprlang::CConfig> m_pConfig; std::unique_ptr<Hyprlang::CConfig> m_pConfig;
@@ -200,14 +227,15 @@ class CConfigManager {
std::string m_szConfigErrors = ""; std::string m_szConfigErrors = "";
// internal methods // internal methods
void setAnimForChildren(SAnimationPropertyConfig* const); void setAnimForChildren(SAnimationPropertyConfig* const);
void updateBlurredLS(const std::string&, const bool); void updateBlurredLS(const std::string&, const bool);
void setDefaultAnimationVars(); void setDefaultAnimationVars();
std::optional<std::string> resetHLConfig(); std::optional<std::string> resetHLConfig();
std::optional<std::string> verifyConfigExists(); static std::optional<std::string> generateConfig(std::string configPath);
void postConfigReload(const Hyprlang::CParseResult& result); static std::optional<std::string> verifyConfigExists();
void reload(); void postConfigReload(const Hyprlang::CParseResult& result);
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); void reload();
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);
}; };
inline std::unique_ptr<CConfigManager> g_pConfigManager; inline std::unique_ptr<CConfigManager> g_pConfigManager;

View File

@@ -11,7 +11,7 @@ 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.c_str()); const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
p_ = PVHYPRLANG->getDataStaticPtr(); p_ = PVHYPRLANG->getDataStaticPtr();

View File

@@ -138,7 +138,7 @@ dwindle {
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
master { master {
new_is_master = true new_status = master
} }
# https://wiki.hyprland.org/Configuring/Variables/#misc # https://wiki.hyprland.org/Configuring/Variables/#misc

View File

@@ -5,6 +5,7 @@
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <filesystem>
#include "../plugins/PluginSystem.hpp" #include "../plugins/PluginSystem.hpp"
#include "../signal-safe.hpp" #include "../signal-safe.hpp"
@@ -104,7 +105,19 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += GIT_COMMIT_HASH; finalCrashReport += GIT_COMMIT_HASH;
finalCrashReport += "\nTag: "; finalCrashReport += "\nTag: ";
finalCrashReport += GIT_TAG; finalCrashReport += GIT_TAG;
finalCrashReport += "\n\n"; finalCrashReport += "\nDate: ";
finalCrashReport += GIT_COMMIT_DATE;
finalCrashReport += "\nFlags:\n";
#ifdef LEGACY_RENDERER
finalCrashReport += "legacyrenderer\n";
#endif
#ifndef ISDEBUG
finalCrashReport += "debug\n";
#endif
#ifdef NO_XWAYLAND
finalCrashReport += "no xwayland\n";
#endif
finalCrashReport += "\n";
if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) { if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) {
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n"; finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";

View File

@@ -1,5 +1,6 @@
#include "HyprCtl.hpp" #include "HyprCtl.hpp"
#include <format>
#include <netinet/in.h> #include <netinet/in.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -10,12 +11,19 @@
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include <sys/poll.h>
#include <filesystem>
#include <ranges>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <typeindex> #include <typeindex>
#include <numeric> #include <numeric>
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
#include <aquamarine/input/Input.hpp>
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../managers/CursorManager.hpp" #include "../managers/CursorManager.hpp"
@@ -24,7 +32,10 @@
#include "../devices/IKeyboard.hpp" #include "../devices/IKeyboard.hpp"
#include "../devices/ITouch.hpp" #include "../devices/ITouch.hpp"
#include "../devices/Tablet.hpp" #include "../devices/Tablet.hpp"
#include "../protocols/GlobalShortcuts.hpp"
#include "debug/RollingLogFollow.hpp"
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "helpers/MiscFunctions.hpp"
static void trimTrailingComma(std::string& str) { static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',') if (!str.empty() && str.back() == ',')
@@ -46,43 +57,27 @@ static std::string formatToString(uint32_t drmFormat) {
static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) { static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) {
std::string result; std::string result;
if (!wl_list_empty(&pMonitor->output->modes)) { for (auto& m : pMonitor->output->modes) {
wlr_output_mode* mode; if (format == FORMAT_NORMAL)
result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0);
wl_list_for_each(mode, &pMonitor->output->modes, link) { else
result += std::format("\"{}x{}@{:.2f}Hz\",", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0);
if (format == FORMAT_NORMAL)
result += std::format("{}x{}@{:.2f}Hz ", mode->width, mode->height, mode->refresh / 1000.0);
else
result += std::format("\"{}x{}@{:.2f}Hz\",", mode->width, mode->height, mode->refresh / 1000.0);
}
result.pop_back();
} }
trimTrailingComma(result);
return result; return result;
} }
std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format) {
CVarList vars(request, 0, ' '); std::string result;
auto allMonitors = false; if (!m->output || m->ID == -1ull)
return "";
if (vars.size() > 2)
return "too many args";
if (vars.size() == 2 && vars[1] == "all")
allMonitors = true;
std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { result += std::format(
if (!m->output || m->ID == -1ull) R"#({{
continue;
result += std::format(
R"#({{
"id": {}, "id": {},
"name": "{}", "name": "{}",
"description": "{}", "description": "{}",
@@ -113,14 +108,46 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
"currentFormat": "{}", "currentFormat": "{}",
"availableModes": [{}] "availableModes": [{}]
}},)#", }},)#",
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make ? m->output->make : ""),
escapeJSONStrings(m->output->model ? m->output->model : ""), escapeJSONStrings(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make), escapeJSONStrings(m->output->model),
(int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspaceID(), escapeJSONStrings(m->output->serial), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
(!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(),
escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"),
(m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
} else {
result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing,
!m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
}
return result;
}
std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
auto allMonitors = false;
if (vars.size() > 2)
return "too many args";
if (vars.size() == 2 && vars[1] == "all")
allMonitors = true;
std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
result += CHyprCtl::getMonitorData(m, format);
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -131,16 +158,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
if (!m->output || m->ID == -1ull) if (!m->output || m->ID == -1ull)
continue; continue;
result += std::format( result +=
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\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"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(), m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
(!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false),
m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format));
} }
} }
@@ -181,7 +208,7 @@ static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) {
return result.str(); return result.str();
} }
static std::string 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_vWindowFocusHistory.size(); ++i) {
if (g_pCompositor->m_vWindowFocusHistory[i].lock() == wnd) if (g_pCompositor->m_vWindowFocusHistory[i].lock() == wnd)
@@ -203,6 +230,7 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"name": "{}" "name": "{}"
}}, }},
"floating": {}, "floating": {},
"pseudo": {},
"monitor": {}, "monitor": {},
"class": "{}", "class": "{}",
"title": "{}", "title": "{}",
@@ -212,8 +240,7 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
"xwayland": {}, "xwayland": {},
"pinned": {}, "pinned": {},
"fullscreen": {}, "fullscreen": {},
"fullscreenMode": {}, "fullscreenClient": {},
"fakeFullscreen": {},
"grouped": [{}], "grouped": [{}],
"tags": [{}], "tags": [{}],
"swallowing": "0x{:x}", "swallowing": "0x{:x}",
@@ -221,22 +248,22 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) {
}},)#", }},)#",
(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_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (int64_t)w->m_iMonitorID, escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"),
escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), (int64_t)w->m_iMonitorID, escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass),
((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
(w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
} else { } else {
return std::format("Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: " return std::format(
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " "Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
"{}\n\txwayland: {}\n\tpinned: " "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", "{}\n\txwayland: {}\n\tpinned: "
(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\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\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_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName),
w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(),
(w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bFakeFullscreenState, getGroupedData(w, format), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format),
getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w));
} }
} }
@@ -249,7 +276,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all)
continue; continue;
result += getWindowData(w, format); result += CHyprCtl::getWindowData(w, format);
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -260,13 +287,13 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all)
continue; continue;
result += getWindowData(w, format); result += CHyprCtl::getWindowData(w, format);
} }
} }
return result; return result;
} }
static std::string 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 = g_pCompositor->getMonitorFromID(w->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID);
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@@ -303,10 +330,10 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
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().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().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.border) ? std::format(",\n \"border\": {}", boolToString(r.border.value())) : ""; const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : "";
const std::string rounding = (bool)(r.rounding) ? std::format(",\n \"rounding\": {}", boolToString(r.rounding.value())) : ""; const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : "";
const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : ""; const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : "";
const std::string shadow = (bool)(r.shadow) ? std::format(",\n \"shadow\": {}", boolToString(r.shadow.value())) : ""; const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : "";
std::string result = std::format(R"#({{ std::string result = std::format(R"#({{
"workspaceString": "{}"{}{}{}{}{}{}{}{} "workspaceString": "{}"{}{}{}{}{}{}{}{}
@@ -325,10 +352,10 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) : std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().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.border) ? boolToString(r.border.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.rounding) ? boolToString(r.rounding.value()) : "<unset>"); const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : "<unset>");
const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>"); const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : "<unset>");
const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.shadow) ? boolToString(r.shadow.value()) : "<unset>"); const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : "<unset>");
std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut,
borderSize, border, rounding, decorate, shadow); borderSize, border, rounding, decorate, shadow);
@@ -346,7 +373,7 @@ std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string requ
if (!valid(w)) if (!valid(w))
return "internal error"; return "internal error";
return getWorkspaceData(w, format); return CHyprCtl::getWorkspaceData(w, format);
} }
std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) { std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) {
@@ -355,7 +382,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request)
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getWorkspaceData(w, format); result += CHyprCtl::getWorkspaceData(w, format);
result += ","; result += ",";
} }
@@ -363,7 +390,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request)
result += "]"; result += "]";
} else { } else {
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getWorkspaceData(w, format); result += CHyprCtl::getWorkspaceData(w, format);
} }
} }
@@ -396,7 +423,7 @@ std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request
if (!validMapped(PWINDOW)) if (!validMapped(PWINDOW))
return format == eHyprCtlOutputFormat::FORMAT_JSON ? "{}" : "Invalid"; return format == eHyprCtlOutputFormat::FORMAT_JSON ? "{}" : "Invalid";
auto result = getWindowData(PWINDOW, format); auto result = CHyprCtl::getWindowData(PWINDOW, format);
if (format == eHyprCtlOutputFormat::FORMAT_JSON) if (format == eHyprCtlOutputFormat::FORMAT_JSON)
result.pop_back(); result.pop_back();
@@ -538,8 +565,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
"defaultSpeed": {:.5f} "defaultSpeed": {:.5f}
}},)#", }},)#",
(uintptr_t)m.get(), escapeJSONStrings(m->hlName), (uintptr_t)m.get(), escapeJSONStrings(m->hlName),
wlr_input_device_is_libinput(&m->wlr()->base) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) : m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f);
0.f);
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -597,9 +623,8 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
R"#( {{ R"#( {{
"address": "0x{:x}", "address": "0x{:x}",
"type": "tabletTool", "type": "tabletTool",
"belongsTo": "0x{:x}"
}},)#", }},)#",
(uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); (uintptr_t)d.get());
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -627,7 +652,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
"address": "0x{:x}", "address": "0x{:x}",
"name": "{}" "name": "{}"
}},)#", }},)#",
(uintptr_t)&d, escapeJSONStrings(d.pWlrDevice ? d.pWlrDevice->name : "")); (uintptr_t)&d, escapeJSONStrings(d.pDevice ? d.pDevice->getName() : ""));
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -640,9 +665,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
for (auto& m : g_pInputManager->m_vPointers) { for (auto& m : g_pInputManager->m_vPointers) {
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->hlName,
(wlr_input_device_is_libinput(&m->wlr()->base) ? (m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f));
libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) :
0.f));
} }
result += "\n\nKeyboards:\n"; result += "\n\nKeyboards:\n";
@@ -661,11 +684,11 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
} }
for (auto& d : g_pInputManager->m_vTablets) { for (auto& d : g_pInputManager->m_vTablets) {
result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->wlr()->width_mm, d->wlr()->height_mm); 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);
} }
for (auto& d : g_pInputManager->m_vTabletTools) { for (auto& d : g_pInputManager->m_vTabletTools) {
result += std::format("\tTablet Tool at {:x} (belongs to {:x})\n", (uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); result += std::format("\tTablet Tool at {:x}\n", (uintptr_t)d.get());
} }
result += "\n\nTouch:\n"; result += "\n\nTouch:\n";
@@ -677,7 +700,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
result += "\n\nSwitches:\n"; result += "\n\nSwitches:\n";
for (auto& d : g_pInputManager->m_lSwitches) { for (auto& d : g_pInputManager->m_lSwitches) {
result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pWlrDevice ? d.pWlrDevice->name : ""); result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pDevice ? d.pDevice->getName() : "");
} }
} }
@@ -753,7 +776,7 @@ std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request)
std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) { std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string ret = ""; std::string ret = "";
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts(); const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts();
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
for (auto& sh : SHORTCUTS) for (auto& sh : SHORTCUTS)
ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description);
@@ -789,9 +812,11 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
ret += "e"; ret += "e";
if (kb.nonConsuming) if (kb.nonConsuming)
ret += "n"; ret += "n";
if (kb.hasDescription)
ret += "d";
ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, kb.key, ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap,
kb.keycode, kb.catchAll, kb.handler, kb.arg); kb.key, kb.keycode, kb.catchAll, kb.description, kb.handler, kb.arg);
} }
} else { } else {
// json // json
@@ -805,17 +830,19 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
"release": {}, "release": {},
"repeat": {}, "repeat": {},
"non_consuming": {}, "non_consuming": {},
"has_description": {},
"modmask": {}, "modmask": {},
"submap": "{}", "submap": "{}",
"key": "{}", "key": "{}",
"keycode": {}, "keycode": {},
"catch_all": {}, "catch_all": {},
"description": "{}",
"dispatcher": "{}", "dispatcher": "{}",
"arg": "{}" "arg": "{}"
}},)#", }},)#",
kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false", kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false",
kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", escapeJSONStrings(kb.handler), kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false",
escapeJSONStrings(kb.arg)); escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg));
} }
trimTrailingComma(ret); trimTrailingComma(ret);
ret += "]"; ret += "]";
@@ -826,7 +853,7 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
auto commitMsg = removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE); auto commitMsg = trim(GIT_COMMIT_MESSAGE);
std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' ');
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
@@ -900,7 +927,10 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request)
#else #else
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
#endif #endif
result += "GPU information: \n" + GPUINFO + "\n\n"; result += "GPU information: \n" + GPUINFO;
if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version"))
result += execAndGet("cat /proc/driver/nvidia/version | grep NVRM");
result += "\n\n";
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n"; result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
@@ -1051,7 +1081,7 @@ std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
request = ""; request = "";
} }
curitem = removeBeginEndSpacesTabs(curitem); curitem = trim(curitem);
}; };
nextItem(); nextItem();
@@ -1104,24 +1134,22 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ
if (PKEYBOARD == g_pInputManager->m_vKeyboards.end()) if (PKEYBOARD == g_pInputManager->m_vKeyboards.end())
return "device not found"; return "device not found";
const auto PWLRKEYBOARD = (*PKEYBOARD)->wlr(); const auto KEEB = *PKEYBOARD;
const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap);
const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->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(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1)
break; break;
activeLayout++; activeLayout++;
} }
if (CMD == "next") { if (CMD == "next")
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1);
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);
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, else {
activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
} else {
int requestedLayout = 0; int requestedLayout = 0;
try { try {
requestedLayout = std::stoi(CMD); requestedLayout = std::stoi(CMD);
@@ -1131,7 +1159,7 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ
return "layout idx out of range of " + std::to_string(LAYOUTS); return "layout idx out of range of " + std::to_string(LAYOUTS);
} }
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, requestedLayout); KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout);
} }
return "ok"; return "ok";
@@ -1181,74 +1209,44 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
const auto PROP = vars[2]; const auto PROP = vars[2];
const auto VAL = vars[3]; const auto VAL = vars[3];
auto noFocus = PWINDOW->m_sAdditionalConfigData.noFocus; bool noFocus = PWINDOW->m_sWindowData.noFocus.valueOrDefault();
bool lock = false;
if (request.ends_with("lock"))
lock = true;
try { try {
if (PROP == "animationstyle") { if (PROP == "animationstyle") {
PWINDOW->m_sAdditionalConfigData.animationStyle = VAL; PWINDOW->m_sWindowData.animationStyle = CWindowOverridableVar(VAL, PRIORITY_SET_PROP);
} else if (PROP == "rounding") {
PWINDOW->m_sAdditionalConfigData.rounding.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoblur") {
PWINDOW->m_sAdditionalConfigData.forceNoBlur.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceopaque") {
PWINDOW->m_sAdditionalConfigData.forceOpaque.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceopaqueoverriden") {
PWINDOW->m_sAdditionalConfigData.forceOpaqueOverridden.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceallowsinput") {
PWINDOW->m_sAdditionalConfigData.forceAllowsInput.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoanims") {
PWINDOW->m_sAdditionalConfigData.forceNoAnims.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoborder") {
PWINDOW->m_sAdditionalConfigData.forceNoBorder.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoshadow") {
PWINDOW->m_sAdditionalConfigData.forceNoShadow.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenodim") {
PWINDOW->m_sAdditionalConfigData.forceNoDim.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nofocus") {
PWINDOW->m_sAdditionalConfigData.noFocus.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "windowdancecompat") {
PWINDOW->m_sAdditionalConfigData.windowDanceCompat.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nomaxsize") {
PWINDOW->m_sAdditionalConfigData.noMaxSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "maxsize") { } else if (PROP == "maxsize") {
PWINDOW->m_sAdditionalConfigData.maxSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock); PWINDOW->m_sWindowData.maxSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
if (lock) { PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sWindowData.maxSize.value().x, PWINDOW->m_vRealSize.goal().x),
PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x), std::min((double)PWINDOW->m_sWindowData.maxSize.value().y, PWINDOW->m_vRealSize.goal().y));
std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y)); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); PWINDOW->setHidden(false);
PWINDOW->setHidden(false);
}
} else if (PROP == "minsize") { } else if (PROP == "minsize") {
PWINDOW->m_sAdditionalConfigData.minSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock); PWINDOW->m_sWindowData.minSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP);
if (lock) { PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sWindowData.minSize.value().x, PWINDOW->m_vRealSize.goal().x),
PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x), std::max((double)PWINDOW->m_sWindowData.minSize.value().y, PWINDOW->m_vRealSize.goal().y));
std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y)); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); PWINDOW->setHidden(false);
PWINDOW->setHidden(false);
}
} else if (PROP == "dimaround") {
PWINDOW->m_sAdditionalConfigData.dimAround.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alphaoverride") {
PWINDOW->m_sSpecialRenderData.alphaOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alpha") { } else if (PROP == "alpha") {
PWINDOW->m_sSpecialRenderData.alpha.forceSetIgnoreLocked(std::stof(VAL), lock); PWINDOW->m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alpha.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactiveoverride") {
PWINDOW->m_sSpecialRenderData.alphaInactiveOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alphainactive") { } else if (PROP == "alphainactive") {
PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock); PWINDOW->m_sWindowData.alphaInactive =
} else if (PROP == "alphafullscreenoverride") { CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
PWINDOW->m_sSpecialRenderData.alphaFullscreenOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alphafullscreen") { } else if (PROP == "alphafullscreen") {
PWINDOW->m_sSpecialRenderData.alphaFullscreen.forceSetIgnoreLocked(std::stof(VAL), lock); PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP);
} else if (PROP == "alphaoverride") {
PWINDOW->m_sWindowData.alpha =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphainactiveoverride") {
PWINDOW->m_sWindowData.alphaInactive =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "alphafullscreenoverride") {
PWINDOW->m_sWindowData.alphaFullscreen =
CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP);
} else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") { } else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") {
CGradientValueData colorData = {}; CGradientValueData colorData = {};
if (vars.size() > 4) { if (vars.size() > 4) {
for (int i = 3; i < static_cast<int>(lock ? vars.size() - 1 : vars.size()); ++i) { for (int i = 3; i < static_cast<int>(vars.size()); ++i) {
const auto TOKEN = vars[i]; const auto TOKEN = vars[i];
if (TOKEN.ends_with("deg")) if (TOKEN.ends_with("deg"))
colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0); colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0);
@@ -1259,19 +1257,22 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
colorData.m_vColors.push_back(configStringToInt(VAL)); colorData.m_vColors.push_back(configStringToInt(VAL));
if (PROP == "activebordercolor") if (PROP == "activebordercolor")
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(colorData, lock); PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
else else
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(colorData, lock); PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP);
} else if (PROP == "forcergbx") { } else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) {
PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock); auto pWindowDataElement = search->second(PWINDOW);
} else if (PROP == "bordersize") { if (VAL == "toggle")
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock); *pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP);
} else if (PROP == "keepaspectratio") { else if (VAL == "unset")
PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock); pWindowDataElement->unset(PRIORITY_SET_PROP);
} else if (PROP == "immediate") { else
PWINDOW->m_sAdditionalConfigData.forceTearing.forceSetIgnoreLocked(configStringToInt(VAL), lock); *pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP);
} else if (PROP == "nearestneighbor") { } else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) {
PWINDOW->m_sAdditionalConfigData.nearestNeighbor.forceSetIgnoreLocked(configStringToInt(VAL), lock); if (VAL == "unset")
search->second(PWINDOW)->unset(PRIORITY_SET_PROP);
else
*(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP);
} else { } else {
return "prop not found"; return "prop not found";
} }
@@ -1279,7 +1280,7 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!(PWINDOW->m_sAdditionalConfigData.noFocus.toUnderlying() == noFocus.toUnderlying())) { if (!(PWINDOW->m_sWindowData.noFocus.valueOrDefault() == noFocus)) {
g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->focusWindow(PLASTWINDOW); g_pCompositor->focusWindow(PLASTWINDOW);
@@ -1305,7 +1306,7 @@ std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request)
request = ""; request = "";
} }
curitem = removeBeginEndSpacesTabs(curitem); curitem = trim(curitem);
}; };
nextItem(); nextItem();
@@ -1374,43 +1375,6 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request)
return result; return result;
} }
static bool addOutput(wlr_backend* backend, const std::string& type, const std::string& name) {
wlr_output* output = nullptr;
if (type.empty() || type == "auto") {
if (wlr_backend_is_wl(backend))
output = wlr_wl_output_create(backend);
else if (wlr_backend_is_headless(backend))
output = wlr_headless_add_output(backend, 1920, 1080);
} else {
if (wlr_backend_is_wl(backend) && type == "wayland")
output = wlr_wl_output_create(backend);
else if (wlr_backend_is_headless(backend) && type == "headless")
output = wlr_headless_add_output(backend, 1920, 1080);
}
if (output && !name.empty())
g_pCompositor->getMonitorFromOutput(output)->szName = name;
return output != nullptr;
}
struct outputData {
std::string type;
std::string name;
bool added;
};
void createOutputIter(wlr_backend* backend, void* data) {
const auto DATA = static_cast<outputData*>(data);
if (DATA->added)
return;
if (addOutput(backend, DATA->type, DATA->name))
DATA->added = true;
}
std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' '); CVarList vars(request, 0, ' ');
@@ -1419,15 +1383,36 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
const auto MODE = vars[1]; const auto MODE = vars[1];
bool added = false;
if (!vars[3].empty()) {
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->szName == vars[3])
return "Name already taken";
}
}
if (MODE == "create" || MODE == "add") { if (MODE == "create" || MODE == "add") {
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.";
outputData result{vars[2], vars[3], false}; for (auto& impl : g_pCompositor->m_pAqBackend->getImplementations() | std::views::reverse) {
auto type = impl->type();
wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result); if (type == Aquamarine::AQ_BACKEND_HEADLESS && (vars[2] == "headless" || vars[2] == "auto")) {
added = true;
impl->createOutput(vars[3]);
break;
}
if (!result.added) if (type == Aquamarine::AQ_BACKEND_WAYLAND && (vars[2] == "wayland" || vars[2] == "auto")) {
added = true;
impl->createOutput(vars[3]);
break;
}
}
if (!added)
return "no backend replied to the request"; return "no backend replied to the request";
} else if (MODE == "destroy" || MODE == "remove") { } else if (MODE == "destroy" || MODE == "remove") {
@@ -1439,7 +1424,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
if (!PMONITOR->createdByUser) if (!PMONITOR->createdByUser)
return "cannot remove a real display. Use the monitor keyword."; return "cannot remove a real display. Use the monitor keyword.";
wlr_output_destroy(PMONITOR->output); PMONITOR->output->destroy();
} }
return "ok"; return "ok";
@@ -1619,6 +1604,10 @@ CHyprCtl::CHyprCtl() {
CHyprCtl::~CHyprCtl() { CHyprCtl::~CHyprCtl() {
if (m_eventSource) if (m_eventSource)
wl_event_source_remove(m_eventSource); wl_event_source_remove(m_eventSource);
if (m_iSocketFD >= 0)
close(m_iSocketFD);
if (!m_socketPath.empty())
unlink(m_socketPath.c_str());
} }
SP<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) { SP<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) {
@@ -1723,6 +1712,46 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) {
return getReply(input); return getReply(input);
} }
bool successWrite(int fd, const std::string& data, bool needLog = true) {
if (write(fd, data.c_str(), data.length()) > 0)
return true;
if (errno == EAGAIN)
return true;
if (needLog)
Debug::log(ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno)));
return false;
}
void runWritingDebugLogThread(const int conn) {
using namespace std::chrono_literals;
Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn);
//will be finished, when reading side close connection
std::thread([conn]() {
while (Debug::RollingLogFollow::Get().IsRunning()) {
if (Debug::RollingLogFollow::Get().isEmpty(conn)) {
std::this_thread::sleep_for(1000ms);
continue;
}
auto line = Debug::RollingLogFollow::Get().GetLog(conn);
if (!successWrite(conn, line))
// We cannot write, when connection is closed. So thread will successfully exit by itself
break;
std::this_thread::sleep_for(100ms);
}
close(conn);
Debug::RollingLogFollow::Get().StopFor(conn);
}).detach();
}
bool isFollowUpRollingLogRequest(const std::string& request) {
return request.contains("rollinglog") && request.contains("f");
}
int hyprCtlFDTick(int fd, uint32_t mask, void* data) { 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;
@@ -1734,13 +1763,17 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
std::array<char, 1024> readBuffer; std::array<char, 1024> readBuffer;
fd_set fdset; //
FD_ZERO(&fdset); pollfd pollfds[1] = {
FD_SET(ACCEPTEDCONNECTION, &fdset); {
timeval timeout = {.tv_sec = 0, .tv_usec = 5000}; .fd = ACCEPTEDCONNECTION,
auto success = select(ACCEPTEDCONNECTION + 1, &fdset, nullptr, nullptr, &timeout); .events = POLLIN,
},
};
if (success <= 0) { int ret = poll(pollfds, 1, 5000);
if (ret <= 0) {
close(ACCEPTEDCONNECTION); close(ACCEPTEDCONNECTION);
return 0; return 0;
} }
@@ -1766,9 +1799,15 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
reply = "Err: " + std::string(e.what()); reply = "Err: " + std::string(e.what());
} }
write(ACCEPTEDCONNECTION, reply.c_str(), reply.length()); successWrite(ACCEPTEDCONNECTION, reply);
close(ACCEPTEDCONNECTION); if (isFollowUpRollingLogRequest(request)) {
Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket.");
Debug::RollingLogFollow::Get().StartFor(ACCEPTEDCONNECTION);
runWritingDebugLogThread(ACCEPTEDCONNECTION);
Debug::log(LOG, Debug::RollingLogFollow::Get().DebugInfo());
} else
close(ACCEPTEDCONNECTION);
if (g_pConfigManager->m_bWantsMonitorReload) if (g_pConfigManager->m_bWantsMonitorReload)
g_pConfigManager->ensureMonitorStatus(); g_pConfigManager->ensureMonitorStatus();
@@ -1777,7 +1816,6 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
} }
void CHyprCtl::startHyprCtlSocket() { void CHyprCtl::startHyprCtlSocket() {
m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (m_iSocketFD < 0) { if (m_iSocketFD < 0) {
@@ -1787,9 +1825,9 @@ void CHyprCtl::startHyprCtlSocket() {
sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX};
std::string socketPath = g_pCompositor->m_szInstancePath + "/.socket.sock"; m_socketPath = g_pCompositor->m_szInstancePath + "/.socket.sock";
strcpy(SERVERADDRESS.sun_path, socketPath.c_str()); strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str());
if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { if (bind(m_iSocketFD, (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.");
@@ -1799,7 +1837,7 @@ void CHyprCtl::startHyprCtlSocket() {
// 10 max queued. // 10 max queued.
listen(m_iSocketFD, 10); listen(m_iSocketFD, 10);
Debug::log(LOG, "Hypr socket started at {}", socketPath); Debug::log(LOG, "Hypr socket started at {}", m_socketPath);
m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
} }

View File

@@ -22,11 +22,16 @@ class CHyprCtl {
bool sysInfoConfig = false; bool sysInfoConfig = false;
} m_sCurrentRequestParams; } m_sCurrentRequestParams;
static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format);
static std::string getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format);
static std::string getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor> m, eHyprCtlOutputFormat format);
private: private:
void startHyprCtlSocket(); void startHyprCtlSocket();
std::vector<SP<SHyprCtlCommand>> m_vCommands; std::vector<SP<SHyprCtlCommand>> m_vCommands;
wl_event_source* m_eventSource = nullptr; wl_event_source* m_eventSource = nullptr;
std::string m_socketPath;
}; };
inline std::unique_ptr<CHyprCtl> g_pHyprCtl; inline std::unique_ptr<CHyprCtl> g_pHyprCtl;

View File

@@ -131,7 +131,7 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
textW /= PANGO_SCALE; textW /= PANGO_SCALE;
textH /= PANGO_SCALE; textH /= PANGO_SCALE;
const auto NOTIFSIZE = Vector2D{textW + 20 + iconW + 2 * ICONPADFORNOTIF, textH + 10}; 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_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);

View File

@@ -1,36 +1,18 @@
#include "Log.hpp" #include "Log.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "RollingLogFollow.hpp"
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
void Debug::init(const std::string& IS) { void Debug::init(const std::string& IS) {
logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
logOfs.open(logFile, std::ios::out | std::ios::app);
} }
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) { void Debug::close() {
if (level > wlr_log_get_verbosity()) logOfs.close();
return;
char* outputStr = nullptr;
vasprintf(&outputStr, fmt, args);
std::string output = std::string(outputStr);
free(outputStr);
rollingLog += output + "\n";
if (!disableLogs || !**disableLogs) {
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
ofs << "[wlr] " << output << "\n";
ofs.close();
}
if (!disableStdout)
std::cout << output << "\n";
} }
void Debug::log(LogLevel level, std::string str) { void Debug::log(LogLevel level, std::string str) {
@@ -73,13 +55,13 @@ void Debug::log(LogLevel level, std::string str) {
if (rollingLog.size() > ROLLING_LOG_SIZE) if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE); rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
if (RollingLogFollow::Get().IsRunning())
RollingLogFollow::Get().AddLog(str);
if (!disableLogs || !**disableLogs) { if (!disableLogs || !**disableLogs) {
// log to a file // log to a file
std::ofstream ofs; logOfs << str << "\n";
ofs.open(logFile, std::ios::out | std::ios::app); logOfs.flush();
ofs << str << "\n";
ofs.close();
} }
// log it to the stdout too. // log it to the stdout too.

View File

@@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <chrono> #include <chrono>
#include <mutex>
#include "../includes.hpp" #include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
@@ -22,6 +23,7 @@ enum LogLevel {
namespace Debug { namespace Debug {
inline std::string logFile; inline std::string logFile;
inline std::ofstream logOfs;
inline int64_t* const* disableLogs = nullptr; inline int64_t* const* disableLogs = nullptr;
inline int64_t* const* disableTime = nullptr; inline int64_t* const* disableTime = nullptr;
inline bool disableStdout = false; inline bool disableStdout = false;
@@ -30,14 +32,18 @@ namespace Debug {
inline int64_t* const* coloredLogs = nullptr; inline int64_t* const* coloredLogs = nullptr;
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
inline std::mutex logMutex;
void init(const std::string& IS); void init(const std::string& IS);
void close();
// //
void log(LogLevel level, std::string str); void log(LogLevel level, std::string str);
template <typename... Args> template <typename... Args>
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) { void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
std::lock_guard<std::mutex> guard(logMutex);
if (level == TRACE && !trace) if (level == TRACE && !trace)
return; return;
@@ -67,6 +73,4 @@ namespace Debug {
log(level, logMsg); log(level, logMsg);
} }
void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
}; };

View File

@@ -0,0 +1,65 @@
#pragma once
#include <shared_mutex>
namespace Debug {
struct RollingLogFollow {
std::unordered_map<int, std::string> socketToRollingLogFollowQueue;
std::shared_mutex m;
bool running = false;
static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192;
// Returns true if the queue is empty for the given socket
bool isEmpty(int socket) {
std::shared_lock<std::shared_mutex> r(m);
return socketToRollingLogFollowQueue[socket].empty();
}
std::string DebugInfo() {
std::shared_lock<std::shared_mutex> r(m);
return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size());
}
std::string GetLog(int socket) {
std::unique_lock<std::shared_mutex> w(m);
const std::string ret = socketToRollingLogFollowQueue[socket];
socketToRollingLogFollowQueue[socket] = "";
return ret;
};
void AddLog(std::string log) {
std::unique_lock<std::shared_mutex> w(m);
running = true;
std::vector<int> to_erase;
for (const auto& p : socketToRollingLogFollowQueue)
socketToRollingLogFollowQueue[p.first] += log + "\n";
}
bool IsRunning() {
std::shared_lock<std::shared_mutex> r(m);
return running;
}
void StopFor(int socket) {
std::unique_lock<std::shared_mutex> w(m);
socketToRollingLogFollowQueue.erase(socket);
if (socketToRollingLogFollowQueue.empty())
running = false;
}
void StartFor(int socket) {
std::unique_lock<std::shared_mutex> w(m);
socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket);
running = true;
}
static RollingLogFollow& Get() {
static RollingLogFollow instance;
static std::mutex gm;
std::lock_guard<std::mutex> lock(gm);
return instance;
};
};
}

View File

@@ -74,7 +74,7 @@ CLayerSurface::~CLayerSurface() {
} }
void CLayerSurface::onDestroy() { void CLayerSurface::onDestroy() {
Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface); Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get());
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
@@ -111,13 +111,24 @@ void CLayerSurface::onDestroy() {
layerSurface.reset(); layerSurface.reset();
if (surface) if (surface)
surface->unassign(); surface->unassign();
listeners.unmap.reset();
listeners.destroy.reset();
listeners.map.reset();
listeners.commit.reset();
} }
void CLayerSurface::onMap() { void CLayerSurface::onMap() {
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface); Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface.get());
mapped = true; mapped = true;
keyboardExclusive = layerSurface->current.interactivity; interactivity = layerSurface->current.interactivity;
layerSurface->surface->map();
// this layer might be re-mapped.
fadingOut = false;
g_pCompositor->removeFromFadingOutSafe(self.lock());
// fix if it changed its mon // fix if it changed its mon
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
@@ -133,12 +144,15 @@ void CLayerSurface::onMap() {
surface->resource()->enter(PMONITOR->self.lock()); surface->resource()->enter(PMONITOR->self.lock());
if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
if (ISEXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(self); g_pInputManager->m_dExclusiveLSes.push_back(self);
const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && const bool GRABSFOCUS = ISEXCLUSIVE ||
// don't focus if constrained (layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
(g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()); // don't focus if constrained
(g_pSeatManager->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
@@ -156,7 +170,7 @@ void CLayerSurface::onMap() {
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
const auto WORKSPACE = PMONITOR->activeWorkspace; const auto WORKSPACE = PMONITOR->activeWorkspace;
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN;
startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
readyToDelete = false; readyToDelete = false;
@@ -170,22 +184,21 @@ void CLayerSurface::onMap() {
} }
void CLayerSurface::onUnmap() { void CLayerSurface::onUnmap() {
Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface); Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface.get());
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace}); g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace});
EMIT_HOOK_EVENT("closeLayer", self.lock()); EMIT_HOOK_EVENT("closeLayer", 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_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
if (!g_pInputManager->m_dExclusiveLSes.empty())
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->surface->resource());
if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) { if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) {
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(self.lock());
mapped = false; mapped = false;
if (layerSurface && layerSurface->surface)
layerSurface->surface->unmap();
startAnimation(false); startAnimation(false);
return; return;
@@ -197,6 +210,8 @@ void CLayerSurface::onUnmap() {
startAnimation(false); startAnimation(false);
mapped = false; mapped = false;
if (layerSurface && layerSurface->surface)
layerSurface->surface->unmap();
g_pCompositor->addToFadingOutSafe(self.lock()); g_pCompositor->addToFadingOutSafe(self.lock());
@@ -204,39 +219,15 @@ void CLayerSurface::onUnmap() {
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
surface.reset();
if (!PMONITOR) if (!PMONITOR)
return; return;
// refocus if needed // refocus if needed
if (WASLASTFOCUS) { // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
g_pInputManager->releaseAllMouseButtons(); if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
g_pInputManager->refocusLastWindow(PMONITOR);
Vector2D surfaceCoords; else if (g_pCompositor->m_pLastFocus)
PHLLS pFoundLayerSurface; g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
SP<CWLSurfaceResource> foundSurface = nullptr;
g_pCompositor->m_pLastFocus.reset();
// find LS-es to focus
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
&surfaceCoords, &pFoundLayerSurface);
if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
&surfaceCoords, &pFoundLayerSurface);
if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) {
// if there isn't any, focus the last window
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PLASTWINDOW);
} else {
// otherwise, full refocus
g_pInputManager->refocus();
}
}
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
@@ -246,12 +237,25 @@ void CLayerSurface::onUnmap() {
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
g_pInputManager->sendMotionEventsToFocused(); g_pInputManager->sendMotionEventsToFocused();
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
} }
void CLayerSurface::onCommit() { void CLayerSurface::onCommit() {
if (!layerSurface) if (!layerSurface)
return; return;
if (!mapped) {
// we're re-mapping if this is the case
if (layerSurface->surface && !layerSurface->surface->current.texture) {
fadingOut = false;
geometry = {};
g_pHyprRenderer->arrangeLayersForMonitor(monitorID);
}
return;
}
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) if (!PMONITOR)
@@ -311,18 +315,35 @@ void CLayerSurface::onCommit() {
realSize.setValueAndWarp(geometry.size()); realSize.setValueAndWarp(geometry.size());
} }
if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained if (mapped) {
&& !keyboardExclusive && mapped) { const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
g_pCompositor->focusSurface(surface->resource()); const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); if (!WASEXCLUSIVE && ISEXCLUSIVE)
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); g_pInputManager->m_dExclusiveLSes.push_back(self);
g_pInputManager->m_bEmptyFocusCursorSet = false; else if (WASEXCLUSIVE && !ISEXCLUSIVE)
} else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
g_pInputManager->refocus();
// if the surface was focused and interactive but now isn't, refocus
if (WASLASTFOCUS && !layerSurface->current.interactivity) {
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
// so unfocus the surface here.
g_pCompositor->focusSurface(nullptr);
g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID));
} else if (!WASEXCLUSIVE && ISEXCLUSIVE) {
// if now exclusive and not previously
g_pSeatManager->setGrab(nullptr);
g_pInputManager->releaseAllMouseButtons();
g_pCompositor->focusSurface(surface->resource());
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y);
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL);
g_pInputManager->m_bEmptyFocusCursorSet = false;
}
} }
keyboardExclusive = layerSurface->current.interactivity; interactivity = layerSurface->current.interactivity;
g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y); g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y);
@@ -405,9 +426,9 @@ 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}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0.0},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y},
PMONITOR->vecPosition + Vector2D{0, PMONITOR->vecSize.y}, PMONITOR->vecPosition + Vector2D{0.0, PMONITOR->vecSize.y},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2},
}; };
@@ -512,4 +533,4 @@ int CLayerSurface::popupsCount() {
int no = -1; // we have one dummy int no = -1; // we have one dummy
popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no);
return no; return no;
} }

View File

@@ -34,40 +34,41 @@ class CLayerSurface {
WP<CLayerShellResource> layerSurface; WP<CLayerShellResource> layerSurface;
wl_list link; wl_list link;
bool keyboardExclusive = false; // the header providing the enum type cannot be imported here
int interactivity = 0;
SP<CWLSurface> surface; SP<CWLSurface> surface;
bool mapped = false; bool mapped = false;
uint32_t layer = 0; uint32_t layer = 0;
int monitorID = -1; int monitorID = -1;
bool fadingOut = false; bool fadingOut = false;
bool readyToDelete = false; bool readyToDelete = false;
bool noProcess = false; bool noProcess = false;
bool noAnimations = false; bool noAnimations = false;
bool forceBlur = false; bool forceBlur = false;
bool forceBlurPopups = false; bool forceBlurPopups = false;
int xray = -1; int xray = -1;
bool ignoreAlpha = false; bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f; float ignoreAlphaValue = 0.f;
bool dimAround = false; bool dimAround = false;
std::optional<std::string> animationStyle; std::optional<std::string> animationStyle;
PHLLSREF self; PHLLSREF self;
CBox geometry = {0, 0, 0, 0}; CBox geometry = {0, 0, 0, 0};
Vector2D position; Vector2D position;
std::string szNamespace = ""; std::string szNamespace = "";
std::unique_ptr<CPopup> popupHead; std::unique_ptr<CPopup> popupHead;
void onDestroy(); void onDestroy();
void onMap(); void onMap();
void onUnmap(); void onUnmap();
void onCommit(); void onCommit();
private: private:
struct { struct {
@@ -83,4 +84,4 @@ class CLayerSurface {
bool operator==(const CLayerSurface& rhs) const { bool operator==(const CLayerSurface& rhs) const {
return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID; return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID;
} }
}; };

View File

@@ -22,7 +22,7 @@ CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner),
m_pWindowOwner = pOwner->m_pWindowOwner; m_pWindowOwner = pOwner->m_pWindowOwner;
m_vLastSize = popup->surface->current.geometry.size(); m_vLastSize = popup->surface->current.geometry.size();
unconstrain(); reposition();
initAllSignals(); initAllSignals();
} }
@@ -55,7 +55,7 @@ void CPopup::initAllSignals() {
} }
void CPopup::onNewPopup(SP<CXDGPopupResource> popup) { void CPopup::onNewPopup(SP<CXDGPopupResource> popup) {
const auto POPUP = m_vChildren.emplace_back(std::make_unique<CPopup>(popup, this)).get(); const auto POPUP = m_vChildren.emplace_back(makeShared<CPopup>(popup, this)).get();
Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP);
} }
@@ -188,18 +188,18 @@ void CPopup::onReposition() {
m_vLastPos = coordsRelativeToParent(); m_vLastPos = coordsRelativeToParent();
unconstrain(); reposition();
} }
void CPopup::unconstrain() { void CPopup::reposition() {
const auto COORDS = t1ParentCoords(); const auto COORDS = t1ParentCoords();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS); const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
if (!PMONITOR) if (!PMONITOR)
return; return;
CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; CBox box = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
m_pResource->applyPositioning(box, COORDS - PMONITOR->vecPosition); m_pResource->applyPositioning(box, COORDS);
} }
Vector2D CPopup::coordsRelativeToParent() { Vector2D CPopup::coordsRelativeToParent() {
@@ -250,7 +250,8 @@ void CPopup::recheckTree() {
} }
void CPopup::recheckChildrenRecursive() { void CPopup::recheckChildrenRecursive() {
for (auto& c : m_vChildren) { auto cpy = m_vChildren;
for (auto& c : cpy) {
c->onCommit(true); c->onCommit(true);
c->recheckChildrenRecursive(); c->recheckChildrenRecursive();
} }

View File

@@ -3,7 +3,7 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include "Subsurface.hpp" #include "Subsurface.hpp"
#include "../helpers/signal/Listener.hpp" #include "../helpers/signal/Signal.hpp"
class CXDGPopupResource; class CXDGPopupResource;
@@ -60,8 +60,8 @@ class CPopup {
bool m_bMapped = false; bool m_bMapped = false;
// //
std::vector<std::unique_ptr<CPopup>> m_vChildren; std::vector<SP<CPopup>> m_vChildren;
std::unique_ptr<CSubsurface> m_pSubsurfaceHead; std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
struct { struct {
CHyprSignalListener newPopup; CHyprSignalListener newPopup;
@@ -74,11 +74,11 @@ class CPopup {
} listeners; } listeners;
void initAllSignals(); void initAllSignals();
void unconstrain(); void reposition();
void recheckChildrenRecursive(); void recheckChildrenRecursive();
void sendScale(); void sendScale();
Vector2D localToGlobal(const Vector2D& rel); Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords(); Vector2D t1ParentCoords();
static void bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data); static void bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data);
}; };

View File

@@ -1,6 +1,7 @@
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/LayerShell.hpp"
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) { void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_pResource = pSurface; m_pResource = pSurface;
@@ -56,12 +57,12 @@ bool CWLSurface::small() const {
if (!validMapped(m_pWindowOwner) || !exists()) if (!validMapped(m_pWindowOwner) || !exists())
return false; return false;
if (!m_pResource->current.buffer) if (!m_pResource->current.texture)
return false; return false;
const auto O = m_pWindowOwner.lock(); const auto O = m_pWindowOwner.lock();
return O->m_vReportedSize.x > m_pResource->current.buffer->size.x + 1 || O->m_vReportedSize.y > m_pResource->current.buffer->size.y + 1; return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1;
} }
Vector2D CWLSurface::correctSmallVec() const { Vector2D CWLSurface::correctSmallVec() const {
@@ -74,33 +75,52 @@ Vector2D CWLSurface::correctSmallVec() const {
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_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize.value() / O->m_vReportedSize);
} }
Vector2D CWLSurface::getViewporterCorrectedSize() const { Vector2D CWLSurface::correctSmallVecBuf() const {
if (!exists() || !m_pResource->current.buffer) if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.texture)
return {}; return {};
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size; const auto SIZE = getViewporterCorrectedSize();
const auto BS = m_pResource->current.bufferSize;
return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY});
} }
CRegion CWLSurface::logicalDamage() const { Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!m_pResource->current.buffer) if (!exists() || !m_pResource->current.texture)
return {};
return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.bufferSize;
}
CRegion CWLSurface::computeDamage() const {
if (!m_pResource->current.texture)
return {}; return {};
CRegion damage = m_pResource->accumulateCurrentBufferDamage(); CRegion damage = m_pResource->accumulateCurrentBufferDamage();
damage.transform(m_pResource->current.transform, m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y); damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y);
damage.scale(1.0 / m_pResource->current.scale);
const auto VPSIZE = getViewporterCorrectedSize(); const auto BUFSIZE = m_pResource->current.bufferSize;
const auto CORRECTVEC = correctSmallVec(); const auto CORRECTVEC = correctSmallVecBuf();
if (m_pResource->current.viewport.hasSource) if (m_pResource->current.viewport.hasSource)
damage.intersect(m_pResource->current.viewport.source); damage.intersect(m_pResource->current.viewport.source);
const auto SCALEDSRCSIZE = const auto SCALEDSRCSIZE = m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.bufferSize;
m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size;
damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y}); damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
damage.translate(CORRECTVEC); damage.translate(CORRECTVEC);
// go from buffer coords in the damage to hl logical
const auto BOX = getSurfaceBoxGlobal();
const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.bufferSize :
Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */};
damage.scale(SCALE);
if (m_pWindowOwner)
damage.scale(m_pWindowOwner->m_fX11SurfaceScaledBy); // fix xwayland:force_zero_scaling stuff that will be fucked by the above a bit
return damage; return damage;
} }
@@ -141,27 +161,27 @@ void CWLSurface::init() {
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this); Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
} }
PHLWINDOW CWLSurface::getWindow() { PHLWINDOW CWLSurface::getWindow() const {
return m_pWindowOwner.lock(); return m_pWindowOwner.lock();
} }
PHLLS CWLSurface::getLayer() { PHLLS CWLSurface::getLayer() const {
return m_pLayerOwner.lock(); return m_pLayerOwner.lock();
} }
CPopup* CWLSurface::getPopup() { CPopup* CWLSurface::getPopup() const {
return m_pPopupOwner; return m_pPopupOwner;
} }
CSubsurface* CWLSurface::getSubsurface() { CSubsurface* CWLSurface::getSubsurface() const {
return m_pSubsurfaceOwner; return m_pSubsurfaceOwner;
} }
bool CWLSurface::desktopComponent() { bool CWLSurface::desktopComponent() const {
return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner; return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner;
} }
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() { std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const {
if (!desktopComponent()) if (!desktopComponent())
return {}; return {};
@@ -181,7 +201,7 @@ void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) {
m_pConstraint = constraint; m_pConstraint = constraint;
} }
SP<CPointerConstraint> CWLSurface::constraint() { SP<CPointerConstraint> CWLSurface::constraint() const {
return m_pConstraint.lock(); return m_pConstraint.lock();
} }
@@ -202,3 +222,11 @@ SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
return nullptr; return nullptr;
return pSurface->hlSurface.lock(); return pSurface->hlSurface.lock();
} }
bool CWLSurface::keyboardFocusable() const {
if (m_pWindowOwner || m_pPopupOwner || m_pSubsurfaceOwner)
return true;
if (m_pLayerOwner && m_pLayerOwner->layerSurface)
return m_pLayerOwner->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
return false;
}

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/Region.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
class CSubsurface; class CSubsurface;
@@ -33,22 +33,24 @@ class CWLSurface {
SP<CWLSurfaceResource> resource() const; SP<CWLSurfaceResource> resource() const;
bool exists() const; bool exists() const;
bool small() const; // means surface is smaller than the requested size bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D correctSmallVecBuf() const; // returns a corrective vector for small() surfaces, in BL coords
Vector2D getViewporterCorrectedSize() const; Vector2D getViewporterCorrectedSize() const;
CRegion logicalDamage() const; CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned
bool visible(); bool visible();
bool keyboardFocusable() const;
// getters for owners. // getters for owners.
PHLWINDOW getWindow(); PHLWINDOW getWindow() const;
PHLLS getLayer(); PHLLS getLayer() const;
CPopup* getPopup(); CPopup* getPopup() const;
CSubsurface* getSubsurface(); CSubsurface* getSubsurface() const;
// desktop components misc utils // desktop components misc utils
std::optional<CBox> getSurfaceBoxGlobal(); std::optional<CBox> getSurfaceBoxGlobal() const;
void appendConstraint(WP<CPointerConstraint> constraint); void appendConstraint(WP<CPointerConstraint> constraint);
SP<CPointerConstraint> constraint(); SP<CPointerConstraint> constraint() const;
// allow stretching. Useful for plugins. // allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false; bool m_bFillIgnoreSmall = false;
@@ -107,7 +109,7 @@ class CWLSurface {
void destroy(); void destroy();
void init(); void init();
bool desktopComponent(); bool desktopComponent() const;
struct { struct {
CHyprSignalListener destroy; CHyprSignalListener destroy;

View File

@@ -1,4 +1,5 @@
#include <any> #include <any>
#include <bit>
#include <string_view> #include <string_view>
#include <algorithm> #include <algorithm>
#include "Window.hpp" #include "Window.hpp"
@@ -12,6 +13,9 @@
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../xwayland/XWayland.hpp" #include "../xwayland/XWayland.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) { PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface)); PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
@@ -101,21 +105,21 @@ CWindow::~CWindow() {
std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return !other.first.lock() || other.first.lock().get() == this; }); std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return !other.first.lock() || other.first.lock().get() == this; });
} }
SWindowDecorationExtents CWindow::getFullWindowExtents() { SBoxExtents CWindow::getFullWindowExtents() {
if (m_bFadingOut) if (m_bFadingOut)
return m_eOriginalClosedExtents; return m_eOriginalClosedExtents;
const int BORDERSIZE = getRealBorderSize(); const int BORDERSIZE = getRealBorderSize();
if (m_sAdditionalConfigData.dimAround) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
} }
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; SBoxExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(m_pSelf.lock()); const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(m_pSelf.lock());
if (EXTENTS.topLeft.x > maxExtents.topLeft.x) if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x; maxExtents.topLeft.x = EXTENTS.topLeft.x;
@@ -167,7 +171,7 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
} }
CBox CWindow::getFullWindowBoundingBox() { CBox CWindow::getFullWindowBoundingBox() {
if (m_sAdditionalConfigData.dimAround) { if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
} }
@@ -189,7 +193,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
auto POS = m_vPosition; auto POS = m_vPosition;
auto SIZE = m_vSize; auto SIZE = m_vSize;
if (m_bIsFullscreen) { if (isFullscreen()) {
POS = PMONITOR->vecPosition; POS = PMONITOR->vecPosition;
SIZE = PMONITOR->vecSize; SIZE = PMONITOR->vecSize;
@@ -215,13 +219,13 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
} }
CBox CWindow::getWindowBoxUnified(uint64_t properties) { CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_sAdditionalConfigData.dimAround) { if (m_sWindowData.dimAround.valueOrDefault()) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR) if (PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
} }
SWindowDecorationExtents EXTENTS = {{0, 0}, {0, 0}}; SBoxExtents EXTENTS = {{0, 0}, {0, 0}};
if (properties & RESERVED_EXTENTS) if (properties & RESERVED_EXTENTS)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock())); EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock()));
if (properties & INPUT_EXTENTS) if (properties & INPUT_EXTENTS)
@@ -239,7 +243,7 @@ CBox CWindow::getWindowMainSurfaceBox() {
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
} }
SWindowDecorationExtents CWindow::getFullWindowReservedArea() { SBoxExtents CWindow::getFullWindowReservedArea() {
return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock()); return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock());
} }
@@ -408,11 +412,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
setAnimationsToMove(); setAnimationsToMove();
g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID); g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID);
g_pCompositor->updateWorkspaceSpecialRenderData(OLDWORKSPACE->m_iID); g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->m_iMonitorID);
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -441,9 +445,11 @@ PHLWINDOW CWindow::X11TransientFor() {
if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent) if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent)
return nullptr; return nullptr;
auto s = m_pXWaylandSurface->parent; auto s = m_pXWaylandSurface->parent;
auto oldParent = s;
while (s) { while (s) {
if (!s->parent) // break cyclic loop of m_pXWaylandSurface being parent of itself, #TODO reject this from even being created?
if (!s->parent || s->parent == oldParent)
break; break;
s = s->parent; s = s->parent;
} }
@@ -472,13 +478,7 @@ void unregisterVar(void* ptr) {
void CWindow::onUnmap() { void CWindow::onUnmap() {
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty"); static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
if (g_pCompositor->m_pLastWindow.lock().get() == this)
g_pCompositor->m_pLastWindow.reset();
if (g_pInputManager->currentlyDraggedWindow.lock().get() == this)
g_pInputManager->currentlyDraggedWindow.reset();
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
if (!m_szInitialWorkspaceToken.empty()) { if (!m_szInitialWorkspaceToken.empty()) {
const auto TOKEN = g_pTokenManager->getToken(m_szInitialWorkspaceToken); const auto TOKEN = g_pTokenManager->getToken(m_szInitialWorkspaceToken);
@@ -519,7 +519,7 @@ void CWindow::onUnmap() {
PMONITOR->solitaryClient.reset(); PMONITOR->solitaryClient.reset();
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -602,38 +602,15 @@ bool CWindow::isHidden() {
} }
void CWindow::applyDynamicRule(const SWindowRule& r) { void CWindow::applyDynamicRule(const SWindowRule& r) {
if (r.szRule == "noblur") { const eOverridePriority priority = r.szValue == "execRule" ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
m_sAdditionalConfigData.forceNoBlur = true; const CVarList VARS(r.szRule, 0, ' ');
} else if (r.szRule == "noborder") { if (r.szRule.starts_with("tag")) {
m_sAdditionalConfigData.forceNoBorder = true;
} else if (r.szRule == "noshadow") {
m_sAdditionalConfigData.forceNoShadow = true;
} else if (r.szRule == "nodim") {
m_sAdditionalConfigData.forceNoDim = true;
} else if (r.szRule == "forcergbx") {
m_sAdditionalConfigData.forceRGBX = true;
} else if (r.szRule == "opaque") {
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule == "immediate") {
m_sAdditionalConfigData.forceTearing = true;
} else if (r.szRule == "nearestneighbor") {
m_sAdditionalConfigData.nearestNeighbor = true;
} else if (r.szRule.starts_with("tag")) {
CVarList vars{r.szRule, 0, 's', true}; CVarList vars{r.szRule, 0, 's', true};
if (vars.size() == 2 && vars[0] == "tag") if (vars.size() == 2 && vars[0] == "tag")
m_tags.applyTag(vars[1], true); m_tags.applyTag(vars[1], true);
else else
Debug::log(ERR, "Tag rule invalid: {}", r.szRule); Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
} else if (r.szRule.starts_with("rounding")) {
try {
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("bordersize")) {
try {
m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
} catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("opacity")) { } else if (r.szRule.starts_with("opacity")) {
try { try {
CVarList vars(r.szRule, 0, ' '); CVarList vars(r.szRule, 0, ' ');
@@ -646,21 +623,18 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
if (r == "override") { if (r == "override") {
if (opacityIDX == 1) if (opacityIDX == 1)
m_sSpecialRenderData.alphaOverride = true; m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
else if (opacityIDX == 2) else if (opacityIDX == 2)
m_sSpecialRenderData.alphaInactiveOverride = true; m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority);
else if (opacityIDX == 3) else if (opacityIDX == 3)
m_sSpecialRenderData.alphaFullscreenOverride = true; m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
} else { } else {
if (opacityIDX == 0) { if (opacityIDX == 0) {
m_sSpecialRenderData.alpha = std::stof(r); m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
m_sSpecialRenderData.alphaOverride = false;
} else if (opacityIDX == 1) { } else if (opacityIDX == 1) {
m_sSpecialRenderData.alphaInactive = std::stof(r); m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
m_sSpecialRenderData.alphaInactiveOverride = false;
} else if (opacityIDX == 2) { } else if (opacityIDX == 2) {
m_sSpecialRenderData.alphaFullscreen = std::stof(r); m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
m_sSpecialRenderData.alphaFullscreenOverride = false;
} else { } else {
throw std::runtime_error("more than 3 alpha values"); throw std::runtime_error("more than 3 alpha values");
} }
@@ -670,29 +644,25 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} }
if (opacityIDX == 1) { if (opacityIDX == 1) {
m_sSpecialRenderData.alphaInactiveOverride = m_sSpecialRenderData.alphaOverride; m_sWindowData.alphaInactive = m_sWindowData.alpha;
m_sSpecialRenderData.alphaInactive = m_sSpecialRenderData.alpha; m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
m_sSpecialRenderData.alphaFullscreenOverride = m_sSpecialRenderData.alphaOverride;
m_sSpecialRenderData.alphaFullscreen = m_sSpecialRenderData.alpha;
} }
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "noanim") {
m_sAdditionalConfigData.forceNoAnims = true;
} else if (r.szRule.starts_with("animation")) { } else if (r.szRule.starts_with("animation")) {
auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
m_sAdditionalConfigData.animationStyle = STYLE; m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority);
} else if (r.szRule.starts_with("bordercolor")) { } else if (r.szRule.starts_with("bordercolor")) {
try { try {
// Each vector will only get used if it has at least one color // Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {}; CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {}; CGradientValueData inactiveBorderGradient = {};
bool active = true; bool active = true;
CVarList colorsAndAngles = CVarList(removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true); CVarList colorsAndAngles = CVarList(trim(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
// Basic form has only two colors, everything else can be parsed as a gradient // Basic form has only two colors, everything else can be parsed as a gradient
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) { if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))); m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))), priority);
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))); m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))), priority);
return; return;
} }
@@ -715,24 +685,24 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
else if (activeBorderGradient.m_vColors.empty()) else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule); Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
else if (inactiveBorderGradient.m_vColors.empty()) else if (inactiveBorderGradient.m_vColors.empty())
m_sSpecialRenderData.activeBorderColor = activeBorderGradient; m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else { else {
m_sSpecialRenderData.activeBorderColor = activeBorderGradient; m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient; m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
} }
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "dimaround") { } else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[0]); search != g_pConfigManager->mbWindowProperties.end()) {
m_sAdditionalConfigData.dimAround = true; if (VARS[1].empty()) {
} else if (r.szRule == "keepaspectratio") { *(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority);
m_sAdditionalConfigData.keepAspectRatio = true; } else {
} else if (r.szRule.starts_with("focusonactivate")) { try {
m_sAdditionalConfigData.focusOnActivate = true; *(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]), priority);
} else if (r.szRule.starts_with("xray")) { } catch (...) {}
CVarList vars(r.szRule, 0, ' '); }
} else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) {
try { try {
m_sAdditionalConfigData.xray = configStringToInt(vars[1]); *(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[1]), priority);
} catch (...) {} } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("idleinhibit")) { } else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
@@ -756,9 +726,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
return; return;
} }
m_sAdditionalConfigData.maxSize = VEC; m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
m_vRealSize = Vector2D(std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().x, m_vRealSize.goal().x), m_vRealSize =
std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().y, m_vRealSize.goal().y)); Vector2D(std::min((double)m_sWindowData.maxSize.value().x, m_vRealSize.goal().x), std::min((double)m_sWindowData.maxSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("minsize")) { } else if (r.szRule.starts_with("minsize")) {
@@ -771,9 +741,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
return; return;
} }
m_sAdditionalConfigData.minSize = VEC; m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
m_vRealSize = Vector2D(std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().x, m_vRealSize.goal().x), m_vRealSize =
std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().y, m_vRealSize.goal().y)); Vector2D(std::max((double)m_sWindowData.minSize.value().x, m_vRealSize.goal().x), std::max((double)m_sWindowData.minSize.value().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal());
if (m_sGroupData.pNextWindow.expired()) if (m_sGroupData.pNextWindow.expired())
setHidden(false); setHidden(false);
@@ -782,30 +752,20 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} }
void CWindow::updateDynamicRules() { void CWindow::updateDynamicRules() {
m_sSpecialRenderData.activeBorderColor = CGradientValueData(); m_sWindowData.alpha.unset(PRIORITY_WINDOW_RULE);
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(); m_sWindowData.alphaInactive.unset(PRIORITY_WINDOW_RULE);
m_sSpecialRenderData.alpha = 1.f; m_sWindowData.alphaFullscreen.unset(PRIORITY_WINDOW_RULE);
m_sSpecialRenderData.alphaInactive = -1.f;
m_sAdditionalConfigData.forceNoBlur = false; unsetWindowData(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.forceNoBorder = false;
m_sAdditionalConfigData.forceNoShadow = false; m_sWindowData.animationStyle.unset(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.forceNoDim = false; m_sWindowData.maxSize.unset(PRIORITY_WINDOW_RULE);
if (!m_sAdditionalConfigData.forceOpaqueOverridden) m_sWindowData.minSize.unset(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.forceOpaque = false;
m_sAdditionalConfigData.maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max()); m_sWindowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.minSize = Vector2D(20, 20); m_sWindowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE);
m_sAdditionalConfigData.forceNoAnims = false;
m_sAdditionalConfigData.animationStyle = std::string(""); m_eIdleInhibitMode = IDLEINHIBIT_NONE;
m_sAdditionalConfigData.rounding = -1;
m_sAdditionalConfigData.dimAround = false;
m_sAdditionalConfigData.forceRGBX = false;
m_sAdditionalConfigData.borderSize = -1;
m_sAdditionalConfigData.keepAspectRatio = false;
m_sAdditionalConfigData.focusOnActivate = false;
m_sAdditionalConfigData.xray = -1;
m_sAdditionalConfigData.forceTearing = false;
m_sAdditionalConfigData.nearestNeighbor = false;
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
m_tags.removeDynamicTags(); m_tags.removeDynamicTags();
@@ -882,7 +842,7 @@ void CWindow::createGroup() {
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock())); addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock()));
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -900,7 +860,7 @@ void CWindow::destroyGroup() {
m_sGroupData.head = false; m_sGroupData.head = false;
updateWindowDecos(); updateWindowDecos();
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -936,7 +896,7 @@ void CWindow::destroyGroup() {
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -1011,8 +971,9 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
return; return;
const auto PCURRENT = getGroupCurrent(); const auto PCURRENT = getGroupCurrent();
const bool FULLSCREEN = PCURRENT->m_bIsFullscreen; const bool FULLSCREEN = PCURRENT->isFullscreen();
const auto WORKSPACE = PCURRENT->m_pWorkspace; const auto WORKSPACE = PCURRENT->m_pWorkspace;
const auto MODE = PCURRENT->m_sFullscreenState.client;
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
@@ -1020,7 +981,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow.lock(); const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow.lock();
if (FULLSCREEN) if (FULLSCREEN)
g_pCompositor->setWindowFullscreen(PCURRENT, false, WORKSPACE->m_efFullscreenMode); g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE);
PCURRENT->setHidden(true); PCURRENT->setHidden(true);
pWindow->setHidden(false); // can remove m_pLastWindow pWindow->setHidden(false); // can remove m_pLastWindow
@@ -1038,7 +999,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
g_pCompositor->focusWindow(pWindow); g_pCompositor->focusWindow(pWindow);
if (FULLSCREEN) if (FULLSCREEN)
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode); g_pCompositor->setWindowFullscreenInternal(pWindow, MODE);
g_pHyprRenderer->damageWindow(pWindow); g_pHyprRenderer->damageWindow(pWindow);
@@ -1137,70 +1098,61 @@ bool CWindow::opaque() {
if (PWORKSPACE->m_fAlpha.value() != 1.f) if (PWORKSPACE->m_fAlpha.value() != 1.f)
return false; return false;
if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.buffer) if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.texture)
return m_pXWaylandSurface->surface->current.buffer->opaque; return m_pXWaylandSurface->surface->current.texture->m_bOpaque;
if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.buffer) if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.texture)
return false; return false;
// TODO: this is wrong // TODO: this is wrong
const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents(); const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents();
if (EXTENTS.w >= m_pXDGSurface->surface->current.buffer->size.x && EXTENTS.h >= m_pXDGSurface->surface->current.buffer->size.y) if (EXTENTS.w >= m_pXDGSurface->surface->current.bufferSize.x && EXTENTS.h >= m_pXDGSurface->surface->current.bufferSize.y)
return true; return true;
return m_pWLSurface->resource()->current.buffer->opaque; return m_pWLSurface->resource()->current.texture->m_bOpaque;
} }
float CWindow::rounding() { float CWindow::rounding() {
static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding"); static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding");
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying(); float rounding = m_sWindowData.rounding.valueOr(*PROUNDING);
return m_sSpecialRenderData.rounding ? rounding : 0; return m_sWindowData.noRounding.valueOrDefault() ? 0 : rounding;
} }
void CWindow::updateSpecialRenderData() { void CWindow::updateWindowData() {
const auto PWORKSPACE = m_pWorkspace; const auto PWORKSPACE = m_pWorkspace;
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
updateSpecialRenderData(WORKSPACERULE); updateWindowData(WORKSPACERULE);
} }
void CWindow::updateSpecialRenderData(const SWorkspaceRule& workspaceRule) { void CWindow::updateWindowData(const SWorkspaceRule& workspaceRule) {
static auto PNOBORDERONFLOATING = CConfigValue<Hyprlang::INT>("general:no_border_on_floating"); static auto PNOBORDERONFLOATING = CConfigValue<Hyprlang::INT>("general:no_border_on_floating");
bool border = true; if (*PNOBORDERONFLOATING)
if (m_bIsFloating && *PNOBORDERONFLOATING == 1) m_sWindowData.noBorder = CWindowOverridableVar(m_bIsFloating, PRIORITY_LAYOUT);
border = false; else
m_sWindowData.noBorder.unset(PRIORITY_LAYOUT);
m_sSpecialRenderData.border = workspaceRule.border.value_or(border); m_sWindowData.borderSize.matchOptional(workspaceRule.borderSize, PRIORITY_WORKSPACE_RULE);
m_sSpecialRenderData.borderSize = workspaceRule.borderSize.value_or(-1); m_sWindowData.decorate.matchOptional(workspaceRule.decorate, PRIORITY_WORKSPACE_RULE);
m_sSpecialRenderData.decorate = workspaceRule.decorate.value_or(true); m_sWindowData.noBorder.matchOptional(workspaceRule.noBorder, PRIORITY_WORKSPACE_RULE);
m_sSpecialRenderData.rounding = workspaceRule.rounding.value_or(true); m_sWindowData.noRounding.matchOptional(workspaceRule.noRounding, PRIORITY_WORKSPACE_RULE);
m_sSpecialRenderData.shadow = workspaceRule.shadow.value_or(true); m_sWindowData.noShadow.matchOptional(workspaceRule.noShadow, PRIORITY_WORKSPACE_RULE);
} }
int CWindow::getRealBorderSize() { int CWindow::getRealBorderSize() {
if (!m_sSpecialRenderData.border || m_sAdditionalConfigData.forceNoBorder || (m_pWorkspace && m_bIsFullscreen && (m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL))) if (m_sWindowData.noBorder.valueOrDefault() || (m_pWorkspace && isEffectiveInternalFSMode(FSMODE_FULLSCREEN)))
return 0; return 0;
if (m_sAdditionalConfigData.borderSize.toUnderlying() != -1)
return m_sAdditionalConfigData.borderSize.toUnderlying();
if (m_sSpecialRenderData.borderSize.toUnderlying() != -1)
return m_sSpecialRenderData.borderSize.toUnderlying();
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size"); static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
return *PBORDERSIZE; return m_sWindowData.borderSize.valueOr(*PBORDERSIZE);
} }
bool CWindow::canBeTorn() { bool CWindow::canBeTorn() {
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint); static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
} return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING;
bool CWindow::shouldSendFullscreenState() {
const auto MODE = m_pWorkspace->m_efFullscreenMode;
return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL)));
} }
void CWindow::setSuspended(bool suspend) { void CWindow::setSuspended(bool suspend) {
@@ -1229,7 +1181,7 @@ void CWindow::setAnimationsToMove() {
void CWindow::onWorkspaceAnimUpdate() { void CWindow::onWorkspaceAnimUpdate() {
// clip box for animated offsets // clip box for animated offsets
if (!m_bIsFloating || m_bPinned || m_bIsFullscreen) { if (!m_bIsFloating || m_bPinned || isFullscreen()) {
m_vFloatingOffset = Vector2D(0, 0); m_vFloatingOffset = Vector2D(0, 0);
return; return;
} }
@@ -1283,6 +1235,14 @@ int CWindow::surfacesCount() {
return no; return no;
} }
bool CWindow::isFullscreen() {
return m_sFullscreenState.internal != FSMODE_NONE;
}
bool CWindow::isEffectiveInternalFSMode(const eFullscreenMode MODE) {
return (eFullscreenMode)std::bit_floor((uint8_t)m_sFullscreenState.internal) == MODE;
}
int CWindow::workspaceID() { int CWindow::workspaceID() {
return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace; return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace;
} }
@@ -1344,8 +1304,7 @@ void CWindow::activate(bool force) {
m_bIsUrgent = true; m_bIsUrgent = true;
if (!force && if (!force && (!m_sWindowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)))
(!(*PFOCUSONACTIVATE || m_sAdditionalConfigData.focusOnActivate) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)))
return; return;
if (m_bIsFloating) if (m_bIsFloating)
@@ -1361,19 +1320,17 @@ void CWindow::onUpdateState() {
if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) { if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
bool fs = requestsFS.value(); bool fs = requestsFS.value();
if (m_bIsMapped) {
if (fs != m_bIsFullscreen && m_bIsMapped) g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value());
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_FULL); }
if (!m_bIsMapped) if (!m_bIsMapped)
m_bWantsInitialFullscreen = fs; m_bWantsInitialFullscreen = fs;
} }
if (requestsMX.has_value() && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) { if (requestsMX.has_value() && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) {
bool fs = requestsMX.value(); if (m_bIsMapped)
g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_MAXIMIZED, requestsMX.value());
if (fs != m_bIsFullscreen && m_bIsMapped)
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_MAXIMIZED);
} }
} }
@@ -1384,6 +1341,7 @@ void CWindow::onUpdateMeta() {
if (m_szTitle != NEWTITLE) { if (m_szTitle != NEWTITLE) {
m_szTitle = NEWTITLE; m_szTitle = NEWTITLE;
g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)this)}); g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)this)});
g_pEventManager->postEvent(SHyprIPCEvent{"windowtitlev2", std::format("{:x},{}", (uintptr_t)this, m_szTitle)});
EMIT_HOOK_EVENT("windowTitle", m_pSelf.lock()); EMIT_HOOK_EVENT("windowTitle", m_pSelf.lock());
if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others
@@ -1477,7 +1435,7 @@ void CWindow::onX11Configure(CBox box) {
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());
if (!m_bIsFloating || m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == m_pSelf) { if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) {
g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true);
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());
@@ -1521,9 +1479,6 @@ void CWindow::onX11Configure(CBox box) {
m_bCreatedOverFullscreen = true; m_bCreatedOverFullscreen = true;
if (!m_sAdditionalConfigData.windowDanceCompat)
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock()); g_pHyprRenderer->damageWindow(m_pSelf.lock());
} }
@@ -1537,3 +1492,67 @@ void CWindow::warpCursor() {
else else
g_pCompositor->warpCursorTo(middle()); g_pCompositor->warpCursorTo(middle());
} }
PHLWINDOW CWindow::getSwallower() {
static auto PSWALLOWREGEX = CConfigValue<std::string>("misc:swallow_regex");
static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex");
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
if (!*PSWALLOW || (*PSWALLOWREGEX).empty())
return nullptr;
// check parent
std::vector<PHLWINDOW> candidates;
pid_t currentPid = getPID();
// walk up the tree until we find someone, 25 iterations max.
for (size_t i = 0; i < 25; ++i) {
currentPid = getPPIDof(currentPid);
if (!currentPid)
break;
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->isHidden())
continue;
if (w->getPID() == currentPid)
candidates.push_back(w);
}
}
if (!(*PSWALLOWREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return !std::regex_match(other->m_szClass, std::regex(*PSWALLOWREGEX)); });
if (candidates.size() <= 0)
return nullptr;
if (!(*PSWALLOWEXREGEX).empty())
std::erase_if(candidates, [&](const auto& other) { return std::regex_match(other->m_szTitle, std::regex(*PSWALLOWEXREGEX)); });
if (candidates.size() <= 0)
return nullptr;
if (candidates.size() == 1)
return candidates.at(0);
// walk up the focus history and find the last focused
for (auto& w : g_pCompositor->m_vWindowFocusHistory) {
if (!w)
continue;
if (std::find(candidates.begin(), candidates.end(), w.lock()) != candidates.end())
return w.lock();
}
// if none are found (??) then just return the first one
return candidates.at(0);
}
void CWindow::unsetWindowData(eOverridePriority priority) {
for (auto const& element : g_pConfigManager->mbWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
for (auto const& element : g_pConfigManager->miWindowProperties) {
element.second(m_pSelf.lock())->unset(priority);
}
}

View File

@@ -6,7 +6,7 @@
#include "../config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include "../helpers/Vector2D.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/signal/Signal.hpp" #include "../helpers/signal/Signal.hpp"
#include "../helpers/TagKeeper.hpp" #include "../helpers/TagKeeper.hpp"
#include "../macros.hpp" #include "../macros.hpp"
@@ -16,6 +16,7 @@
#include "Popup.hpp" #include "Popup.hpp"
#include "Subsurface.hpp" #include "Subsurface.hpp"
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "Workspace.hpp"
class CXDGSurfaceResource; class CXDGSurfaceResource;
class CXWaylandSurface; class CXWaylandSurface;
@@ -59,122 +60,130 @@ enum eSuppressEvents {
class IWindowTransformer; class IWindowTransformer;
struct SAlphaValue {
float m_fAlpha;
bool m_bOverride;
float applyAlpha(float alpha) {
if (m_bOverride)
return m_fAlpha;
else
return m_fAlpha * alpha;
};
};
enum eOverridePriority {
PRIORITY_LAYOUT,
PRIORITY_WORKSPACE_RULE,
PRIORITY_WINDOW_RULE,
PRIORITY_SET_PROP,
};
template <typename T> template <typename T>
class CWindowOverridableVar { class CWindowOverridableVar {
public: public:
CWindowOverridableVar(T val) { CWindowOverridableVar(T const& value, eOverridePriority priority) {
value = val; values[priority] = value;
}
CWindowOverridableVar(T const& value) {
defaultValue = value;
} }
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default; ~CWindowOverridableVar() = default;
CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> other) { CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> const& other) {
if (locked) // Self-assignment check
if (this == &other)
return *this; return *this;
locked = other.locked; for (auto const& value : other.values) {
value = other.value; values[value.first] = value.second;
}
return *this; return *this;
} }
T operator=(T& other) { void unset(eOverridePriority priority) {
if (locked) values.erase(priority);
return value;
value = other;
return other;
} }
void forceSetIgnoreLocked(T val, bool lock = false) { bool hasValue() {
value = val; return !values.empty();
locked = lock;
} }
T operator*(T& other) { T value() {
return value * other; if (!values.empty())
return std::prev(values.end())->second;
else
throw std::bad_optional_access();
} }
T operator+(T& other) { T valueOr(T const& other) {
return value + other; if (hasValue())
return value();
else
return other;
} }
bool operator==(T& other) { T valueOrDefault() {
return other == value; return valueOr(defaultValue);
} }
bool operator>=(T& other) { eOverridePriority getPriority() {
return value >= other; if (!values.empty())
return std::prev(values.end())->first;
else
throw std::bad_optional_access();
} }
bool operator<=(T& other) { void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
return value <= other; if (optValue.has_value())
values[priority] = optValue.value();
else
unset(priority);
} }
bool operator>(T& other) {
return value > other;
}
bool operator<(T& other) {
return value < other;
}
explicit operator bool() {
return static_cast<bool>(value);
}
T toUnderlying() {
return value;
}
bool locked = false;
private: private:
T value; std::map<eOverridePriority, T> values;
T defaultValue; // used for toggling, so required for bool
}; };
struct SWindowSpecialRenderData { struct SWindowData {
CWindowOverridableVar<bool> alphaOverride = false; CWindowOverridableVar<SAlphaValue> alpha = SAlphaValue{1.f, false};
CWindowOverridableVar<float> alpha = 1.f; CWindowOverridableVar<SAlphaValue> alphaInactive = SAlphaValue{1.f, false};
CWindowOverridableVar<bool> alphaInactiveOverride = false; CWindowOverridableVar<SAlphaValue> alphaFullscreen = SAlphaValue{1.f, false};
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
CWindowOverridableVar<bool> alphaFullscreenOverride = false;
CWindowOverridableVar<float> alphaFullscreen = -1.f; // -1 means unset
CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset CWindowOverridableVar<bool> allowsInput = false;
CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset CWindowOverridableVar<bool> dimAround = false;
CWindowOverridableVar<bool> decorate = true;
CWindowOverridableVar<bool> focusOnActivate = false;
CWindowOverridableVar<bool> keepAspectRatio = false;
CWindowOverridableVar<bool> nearestNeighbor = false;
CWindowOverridableVar<bool> noAnim = false;
CWindowOverridableVar<bool> noBorder = false;
CWindowOverridableVar<bool> noBlur = false;
CWindowOverridableVar<bool> noDim = false;
CWindowOverridableVar<bool> noFocus = false;
CWindowOverridableVar<bool> noMaxSize = false;
CWindowOverridableVar<bool> noRounding = false;
CWindowOverridableVar<bool> noShadow = false;
CWindowOverridableVar<bool> noShortcutsInhibit = false;
CWindowOverridableVar<bool> opaque = false;
CWindowOverridableVar<bool> RGBX = false;
CWindowOverridableVar<bool> syncFullscreen = true;
CWindowOverridableVar<bool> tearing = false;
CWindowOverridableVar<bool> xray = false;
// set by the layout CWindowOverridableVar<int> rounding;
CWindowOverridableVar<int> borderSize = -1; // -1 means unset CWindowOverridableVar<int> borderSize;
bool rounding = true;
bool border = true;
bool decorate = true;
bool shadow = true;
};
struct SWindowAdditionalConfigData { CWindowOverridableVar<std::string> animationStyle;
std::string animationStyle = std::string(""); CWindowOverridableVar<Vector2D> maxSize;
CWindowOverridableVar<int> rounding = -1; // -1 means no CWindowOverridableVar<Vector2D> minSize;
CWindowOverridableVar<bool> forceNoBlur = false;
CWindowOverridableVar<bool> forceOpaque = false; CWindowOverridableVar<CGradientValueData> activeBorderColor;
CWindowOverridableVar<bool> forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher. CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
CWindowOverridableVar<bool> forceAllowsInput = false;
CWindowOverridableVar<bool> forceNoAnims = false;
CWindowOverridableVar<bool> forceNoBorder = false;
CWindowOverridableVar<bool> forceNoShadow = false;
CWindowOverridableVar<bool> forceNoDim = false;
CWindowOverridableVar<bool> noFocus = false;
CWindowOverridableVar<bool> windowDanceCompat = false;
CWindowOverridableVar<bool> noMaxSize = false;
CWindowOverridableVar<Vector2D> maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
CWindowOverridableVar<Vector2D> minSize = Vector2D(20, 20);
CWindowOverridableVar<bool> dimAround = false;
CWindowOverridableVar<bool> forceRGBX = false;
CWindowOverridableVar<bool> keepAspectRatio = false;
CWindowOverridableVar<bool> focusOnActivate = false;
CWindowOverridableVar<int> xray = -1; // -1 means unset, takes precedence over the renderdata one
CWindowOverridableVar<int> borderSize = -1; // -1 means unset, takes precedence over the renderdata one
CWindowOverridableVar<bool> forceTearing = false;
CWindowOverridableVar<bool> nearestNeighbor = false;
}; };
struct SWindowRule { struct SWindowRule {
@@ -201,6 +210,11 @@ struct SInitialWorkspaceToken {
std::string workspace; std::string workspace;
}; };
struct sFullscreenState {
eFullscreenMode internal = FSMODE_NONE;
eFullscreenMode client = FSMODE_NONE;
};
class CWindow { class CWindow {
public: public:
static PHLWINDOW create(SP<CXDGSurfaceResource>); static PHLWINDOW create(SP<CXDGSurfaceResource>);
@@ -249,24 +263,23 @@ class CWindow {
Vector2D m_vPseudoSize = Vector2D(1280, 720); Vector2D m_vPseudoSize = Vector2D(1280, 720);
// for recovering relative cursor position // for recovering relative cursor position
Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1); Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1);
bool m_bFirstMap = false; // for layouts bool m_bFirstMap = false; // for layouts
bool m_bIsFloating = false; bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bIsFullscreen = false; bool m_bWasMaximized = false;
bool m_bDontSendFullscreen = false; sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
bool m_bWasMaximized = false; uint64_t m_iMonitorID = -1;
uint64_t m_iMonitorID = -1; std::string m_szTitle = "";
std::string m_szTitle = ""; std::string m_szClass = "";
std::string m_szClass = ""; std::string m_szInitialTitle = "";
std::string m_szInitialTitle = ""; std::string m_szInitialClass = "";
std::string m_szInitialClass = ""; PHLWORKSPACE m_pWorkspace;
PHLWORKSPACE m_pWorkspace;
bool m_bIsMapped = false; bool m_bIsMapped = false;
bool m_bRequestsFloat = false; bool m_bRequestsFloat = false;
// This is for fullscreen apps // This is for fullscreen apps
bool m_bCreatedOverFullscreen = false; bool m_bCreatedOverFullscreen = false;
@@ -306,7 +319,7 @@ class CWindow {
bool m_bReadyToDelete = false; bool m_bReadyToDelete = false;
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
Vector2D m_vOriginalClosedSize; // drawing the closing animations Vector2D m_vOriginalClosedSize; // drawing the closing animations
SWindowDecorationExtents m_eOriginalClosedExtents; SBoxExtents m_eOriginalClosedExtents;
bool m_bAnimatingIn = false; bool m_bAnimatingIn = false;
// For pinned (sticky) windows // For pinned (sticky) windows
@@ -315,9 +328,6 @@ class CWindow {
// urgency hint // urgency hint
bool m_bIsUrgent = false; bool m_bIsUrgent = false;
// fakefullscreen
bool m_bFakeFullscreenState = 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_pLastCycledWindow;
@@ -327,8 +337,7 @@ class CWindow {
std::vector<IHyprWindowDecoration*> m_vDecosToRemove; std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
// Special render data, rules, etc // Special render data, rules, etc
SWindowSpecialRenderData m_sSpecialRenderData; SWindowData m_sWindowData;
SWindowAdditionalConfigData m_sAdditionalConfigData;
// Transformers // Transformers
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers; std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
@@ -382,74 +391,78 @@ class CWindow {
} }
// methods // methods
CBox getFullWindowBoundingBox(); CBox getFullWindowBoundingBox();
SWindowDecorationExtents getFullWindowExtents(); SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props); CBox getWindowBoxUnified(uint64_t props);
CBox getWindowMainSurfaceBox(); CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved(); CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco); void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
void updateWindowDecos(); void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco); void removeWindowDeco(IHyprWindowDecoration* deco);
void uncacheWindowDecos(); void uncacheWindowDecos();
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {}); bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
pid_t getPID(); pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType); IHyprWindowDecoration* getDecorationByType(eDecorationType);
void removeDecorationByType(eDecorationType); void removeDecorationByType(eDecorationType);
void updateToplevel(); void updateToplevel();
void updateSurfaceScaleTransformDetails(bool force = false); void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE); void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW X11TransientFor(); PHLWINDOW X11TransientFor();
void onUnmap(); void onUnmap();
void onMap(); void onMap();
void setHidden(bool hidden); void setHidden(bool hidden);
bool isHidden(); bool isHidden();
void applyDynamicRule(const SWindowRule& r); void applyDynamicRule(const SWindowRule& r);
void updateDynamicRules(); void updateDynamicRules();
SWindowDecorationExtents getFullWindowReservedArea(); SBoxExtents getFullWindowReservedArea();
Vector2D middle(); Vector2D middle();
bool opaque(); bool opaque();
float rounding(); float rounding();
bool canBeTorn(); bool canBeTorn();
bool shouldSendFullscreenState(); void setSuspended(bool suspend);
void setSuspended(bool suspend); bool visibleOnMonitor(CMonitor* pMonitor);
bool visibleOnMonitor(CMonitor* pMonitor); int workspaceID();
int workspaceID(); bool onSpecialWorkspace();
bool onSpecialWorkspace(); void activate(bool force = false);
void activate(bool force = false); int surfacesCount();
int surfacesCount();
int getRealBorderSize(); bool isFullscreen();
void updateSpecialRenderData(); bool isEffectiveInternalFSMode(const eFullscreenMode);
void updateSpecialRenderData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(void* ptr); int getRealBorderSize();
bool isInCurvedCorner(double x, double y); void updateWindowData();
bool hasPopupAt(const Vector2D& pos); void updateWindowData(const struct SWorkspaceRule&);
int popupsCount();
void applyGroupRules(); void onBorderAngleAnimEnd(void* ptr);
void createGroup(); bool isInCurvedCorner(double x, double y);
void destroyGroup(); bool hasPopupAt(const Vector2D& pos);
PHLWINDOW getGroupHead(); int popupsCount();
PHLWINDOW getGroupTail();
PHLWINDOW getGroupCurrent(); void applyGroupRules();
PHLWINDOW getGroupPrevious(); void createGroup();
PHLWINDOW getGroupWindowByIndex(int); void destroyGroup();
int getGroupSize(); PHLWINDOW getGroupHead();
bool canBeGroupedInto(PHLWINDOW pWindow); PHLWINDOW getGroupTail();
void setGroupCurrent(PHLWINDOW pWindow); PHLWINDOW getGroupCurrent();
void insertWindowToGroup(PHLWINDOW pWindow); PHLWINDOW getGroupPrevious();
void updateGroupOutputs(); PHLWINDOW getGroupWindowByIndex(int);
void switchWithWindowInGroup(PHLWINDOW pWindow); int getGroupSize();
void setAnimationsToMove(); bool canBeGroupedInto(PHLWINDOW pWindow);
void onWorkspaceAnimUpdate(); void setGroupCurrent(PHLWINDOW pWindow);
void onUpdateState(); void insertWindowToGroup(PHLWINDOW pWindow);
void onUpdateMeta(); void updateGroupOutputs();
void onX11Configure(CBox box); void switchWithWindowInGroup(PHLWINDOW pWindow);
void onResourceChangeX11(); void setAnimationsToMove();
std::string fetchTitle(); void onWorkspaceAnimUpdate();
std::string fetchClass(); void onUpdateState();
void warpCursor(); void onUpdateMeta();
void onX11Configure(CBox box);
void onResourceChangeX11();
std::string fetchTitle();
std::string fetchClass();
void warpCursor();
PHLWINDOW getSwallower();
void unsetWindowData(eOverridePriority priority);
// listeners // listeners
void onAck(uint32_t serial); void onAck(uint32_t serial);

View File

@@ -2,6 +2,9 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) { PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) {
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmtpy); PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmtpy);
workspace->init(workspace); workspace->init(workspace);
@@ -54,6 +57,13 @@ void CWorkspace::init(PHLWORKSPACE self) {
EMIT_HOOK_EVENT("createWorkspace", this); EMIT_HOOK_EVENT("createWorkspace", this);
} }
SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName(bool perMonitor) const {
if (perMonitor)
return m_sPrevWorkspacePerMonitor;
return m_sPrevWorkspace;
}
CWorkspace::~CWorkspace() { CWorkspace::~CWorkspace() {
m_vRenderOffset.unregister(); m_vRenderOffset.unregister();
@@ -101,24 +111,24 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
if (ANIMSTYLE.starts_with("slidefadevert")) { if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) { if (in) {
m_fAlpha.setValueAndWarp(0.f); m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
m_fAlpha = 1.f; m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_fAlpha.setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f; m_fAlpha = 0.f;
m_vRenderOffset = Vector2D(0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
} }
} else { } else {
if (in) { if (in) {
m_fAlpha.setValueAndWarp(0.f); m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0)); m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0));
m_fAlpha = 1.f; m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_fAlpha.setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f; m_fAlpha = 0.f;
m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0); m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0);
} }
} }
} else if (ANIMSTYLE == "fade") { } else if (ANIMSTYLE == "fade") {
@@ -139,10 +149,10 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) { if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? YDISTANCE : -YDISTANCE)); m_vRenderOffset.setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_vRenderOffset = Vector2D(0, left ? -YDISTANCE : YDISTANCE); m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
} }
} else { } else {
// fallback is slide // fallback is slide
@@ -152,10 +162,10 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) { if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0)); m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
m_vRenderOffset = Vector2D(0, 0); m_vRenderOffset = Vector2D(0, 0);
} else { } else {
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0); m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
} }
} }
@@ -193,7 +203,7 @@ PHLWINDOW CWorkspace::getLastFocusedWindow() {
void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) { void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
if (!prev) { if (!prev) {
m_sPrevWorkspace.iID = -1; m_sPrevWorkspace.id = -1;
m_sPrevWorkspace.name = ""; m_sPrevWorkspace.name = "";
return; return;
} }
@@ -203,8 +213,13 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
return; return;
} }
m_sPrevWorkspace.iID = prev->m_iID; m_sPrevWorkspace.id = prev->m_iID;
m_sPrevWorkspace.name = prev->m_szName; m_sPrevWorkspace.name = prev->m_szName;
if (prev->m_iMonitorID == m_iMonitorID) {
m_sPrevWorkspacePerMonitor.id = prev->m_iID;
m_sPrevWorkspacePerMonitor.name = prev->m_szName;
}
} }
std::string CWorkspace::getConfigName() { std::string CWorkspace::getConfigName() {
@@ -219,15 +234,13 @@ std::string CWorkspace::getConfigName() {
} }
bool CWorkspace::matchesStaticSelector(const std::string& selector_) { bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
auto selector = removeBeginEndSpacesTabs(selector_); auto selector = trim(selector_);
if (selector.empty()) if (selector.empty())
return true; return true;
if (isNumber(selector)) { if (isNumber(selector)) {
const auto& [wsid, wsname] = getWorkspaceIDNameFromString(selector);
std::string wsname = "";
int wsid = getWorkspaceIDFromString(selector, wsname);
if (wsid == WORKSPACE_INVALID) if (wsid == WORKSPACE_INVALID)
return false; return false;
@@ -467,16 +480,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false; return false;
break; break;
case 0: // fullscreen full case 0: // fullscreen full
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_FULL) if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_FULLSCREEN)
return false; return false;
break; break;
case 1: // maximized case 1: // maximized
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_MAXIMIZED) if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_MAXIMIZED)
return false;
break;
case 2: // fullscreen without sending fullscreen state to window
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_FULL || !g_pCompositor->getFullscreenWindowOnWorkspace(m_iID) ||
!g_pCompositor->getFullscreenWindowOnWorkspace(m_iID)->m_bDontSendFullscreen)
return false; return false;
break; break;
default: break; default: break;

View File

@@ -4,11 +4,13 @@
#include <string> #include <string>
#include "../defines.hpp" #include "../defines.hpp"
#include "DesktopTypes.hpp" #include "DesktopTypes.hpp"
#include "../helpers/MiscFunctions.hpp"
enum eFullscreenMode : int8_t { enum eFullscreenMode : int8_t {
FULLSCREEN_INVALID = -1, FSMODE_NONE = 0,
FULLSCREEN_FULL = 0, FSMODE_MAXIMIZED = 1 << 0,
FULLSCREEN_MAXIMIZED FSMODE_FULLSCREEN = 1 << 1,
FSMODE_MAX = (1 << 2) - 1
}; };
class CWindow; class CWindow;
@@ -25,17 +27,14 @@ class CWorkspace {
int m_iID = -1; int m_iID = -1;
std::string m_szName = ""; std::string m_szName = "";
uint64_t m_iMonitorID = -1; uint64_t m_iMonitorID = -1;
// Previous workspace ID 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.
struct SPrevWorkspaceData { SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor;
int iID = -1;
std::string name = "";
} m_sPrevWorkspace;
bool m_bHasFullscreenWindow = false; bool m_bHasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL; eFullscreenMode m_efFullscreenMode = FSMODE_NONE;
wl_array m_wlrCoordinateArr; wl_array m_wlrCoordinateArr;
// for animations // for animations
CAnimatedVariable<Vector2D> m_vRenderOffset; CAnimatedVariable<Vector2D> m_vRenderOffset;
@@ -63,21 +62,23 @@ class CWorkspace {
bool m_bPersistent = false; bool m_bPersistent = 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();
void startAnim(bool in, bool left, bool instant = false); void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on); void setActive(bool on);
void moveToMonitor(const int&); void moveToMonitor(const int&);
PHLWINDOW getLastFocusedWindow(); PHLWINDOW getLastFocusedWindow();
void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);
std::string getConfigName(); std::string getConfigName();
bool matchesStaticSelector(const std::string& selector); bool matchesStaticSelector(const std::string& selector);
void markInert(); void markInert();
SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const;
private: private:
void init(PHLWORKSPACE self); void init(PHLWORKSPACE self);

View File

@@ -1,8 +1,22 @@
#include "IKeyboard.hpp" #include "IKeyboard.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../helpers/VarList.hpp" #include "../helpers/varlist/VarList.hpp"
#include "../managers/input/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../managers/SeatManager.hpp"
#include "../config/ConfigManager.hpp"
#include <sys/mman.h>
#include <aquamarine/input/Input.hpp>
#include <cstring>
#define LED_COUNT 3
constexpr static std::array<const char*, 8> MODNAMES = {
XKB_MOD_NAME_SHIFT, XKB_MOD_NAME_CAPS, XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT, XKB_MOD_NAME_NUM, "Mod3", XKB_MOD_NAME_LOGO, "Mod5",
};
constexpr static std::array<const char*, 3> LEDNAMES = {XKB_LED_NAME_NUM, XKB_LED_NAME_CAPS, XKB_LED_NAME_SCROLL};
//
uint32_t IKeyboard::getCapabilities() { uint32_t IKeyboard::getCapabilities() {
return HID_INPUT_CAPABILITY_KEYBOARD; return HID_INPUT_CAPABILITY_KEYBOARD;
} }
@@ -14,27 +28,167 @@ eHIDType IKeyboard::getType() {
IKeyboard::~IKeyboard() { IKeyboard::~IKeyboard() {
events.destroy.emit(); events.destroy.emit();
if (!xkbTranslationState) clearManuallyAllocd();
return; }
xkb_state_unref(xkbTranslationState); void IKeyboard::clearManuallyAllocd() {
xkbTranslationState = nullptr; if (xkbStaticState)
xkb_state_unref(xkbStaticState);
if (xkbState)
xkb_state_unref(xkbState);
if (xkbKeymap)
xkb_keymap_unref(xkbKeymap);
if (xkbKeymapFD >= 0)
close(xkbKeymapFD);
xkbKeymap = nullptr;
xkbState = nullptr;
xkbStaticState = nullptr;
xkbKeymapFD = -1;
}
void IKeyboard::setKeymap(const SStringRuleNames& rules) {
if (keymapOverridden) {
Debug::log(LOG, "Ignoring setKeymap: keymap is overridden");
return;
}
currentRules = rules;
xkb_rule_names XKBRULES = {
.rules = rules.rules.c_str(),
.model = rules.model.c_str(),
.layout = rules.layout.c_str(),
.variant = rules.variant.c_str(),
.options = rules.options.c_str(),
};
const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!CONTEXT) {
Debug::log(ERR, "setKeymap: CONTEXT null??");
return;
}
clearManuallyAllocd();
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);
if (!xkbFilePath.empty()) {
auto path = absolutePath(xkbFilePath, g_pConfigManager->configCurrentPath);
if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE)
Debug::log(ERR, "Cannot open input:kb_file= file for reading");
else {
xkbKeymap = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
fclose(KEYMAPFILE);
}
}
if (!xkbKeymap)
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!xkbKeymap) {
g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant +
", options: " + rules.options + ", layout: " + rules.layout + " )");
Debug::log(ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model,
rules.options);
memset(&XKBRULES, 0, sizeof(XKBRULES));
currentRules.rules = "";
currentRules.model = "";
currentRules.variant = "";
currentRules.options = "";
currentRules.layout = "us";
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
updateXKBTranslationState(xkbKeymap);
const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default");
if (NUMLOCKON == 1) {
// lock numlock
const auto IDX = xkb_map_mod_get_index(xkbKeymap, XKB_MOD_NAME_NUM);
if (IDX != XKB_MOD_INVALID)
modifiersState.locked |= (uint32_t)1 << IDX;
updateModifiers(modifiersState.depressed, modifiersState.latched, modifiersState.locked, modifiersState.group);
}
for (size_t i = 0; i < LEDNAMES.size(); ++i) {
ledIndexes.at(i) = xkb_map_led_get_index(xkbKeymap, LEDNAMES.at(i));
Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES.at(i), ledIndexes.at(i));
}
for (size_t i = 0; i < MODNAMES.size(); ++i) {
modIndexes.at(i) = xkb_map_mod_get_index(xkbKeymap, MODNAMES.at(i));
Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i));
}
updateKeymapFD();
xkb_context_unref(CONTEXT);
g_pSeatManager->updateActiveKeyboardData();
}
void IKeyboard::updateKeymapFD() {
Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName);
if (xkbKeymapFD >= 0)
close(xkbKeymapFD);
xkbKeymapFD = -1;
auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
xkbKeymapString = cKeymapStr;
free(cKeymapStr);
int rw, ro;
if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro))
Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap");
else {
auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0);
close(rw);
if (keymapFDDest == MAP_FAILED) {
Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap");
close(ro);
} else {
memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length());
munmap(keymapFDDest, xkbKeymapString.length() + 1);
xkbKeymapFD = ro;
}
}
Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD);
} }
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
if (xkbTranslationState) if (xkbStaticState)
xkb_state_unref(xkbTranslationState); xkb_state_unref(xkbStaticState);
if (xkbState)
xkb_state_unref(xkbState);
xkbState = nullptr;
xkbStaticState = 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);
xkbTranslationState = xkb_state_new(keymap); xkbStaticState = xkb_state_new(keymap);
xkbState = xkb_state_new(keymap);
return; return;
} }
const auto WLRKB = wlr(); const auto KEYMAP = xkbKeymap;
const auto KEYMAP = WLRKB->keymap; const auto STATE = xkbState;
const auto STATE = WLRKB->xkb_state;
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);
@@ -73,7 +227,8 @@ 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);
} }
xkbTranslationState = xkb_state_new(KEYMAP); xkbState = xkb_state_new(KEYMAP);
xkbStaticState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP); xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT); xkb_context_unref(PCONTEXT);
@@ -94,16 +249,16 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
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);
xkbTranslationState = xkb_state_new(NEWKEYMAP); xkbState = xkb_state_new(NEWKEYMAP);
xkbStaticState = 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 WLRKB = wlr(); const auto KEYMAP = xkbKeymap;
const auto KEYMAP = WLRKB->keymap; const auto STATE = xkbState;
const auto STATE = WLRKB->xkb_state;
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) {
@@ -119,29 +274,118 @@ std::string IKeyboard::getActiveLayout() {
return "none"; return "none";
} }
void IKeyboard::updateLEDs() { std::optional<uint32_t> IKeyboard::getLEDs() {
auto keyboard = wlr(); if (xkbState == nullptr)
return {};
if (!keyboard || keyboard->xkb_state == nullptr)
return;
uint32_t leds = 0; uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) { for (uint32_t i = 0; i < LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i])) if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i)))
leds |= (1 << i); leds |= (1 << i);
} }
updateLEDs(leds); return leds;
}
void IKeyboard::updateLEDs() {
std::optional<uint32_t> leds = getLEDs();
if (!leds.has_value())
return;
updateLEDs(leds.value());
} }
void IKeyboard::updateLEDs(uint32_t leds) { void IKeyboard::updateLEDs(uint32_t leds) {
auto keyboard = wlr(); if (!xkbState)
if (!keyboard || keyboard->xkb_state == nullptr)
return; return;
if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock())) if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock()))
return; return;
wlr_keyboard_led_update(keyboard, leds); if (!aq())
return;
aq()->updateLEDs(leds);
}
uint32_t IKeyboard::getModifiers() {
uint32_t modMask = modifiersState.depressed | modifiersState.latched;
uint32_t mods = 0;
for (size_t i = 0; i < modIndexes.size(); ++i) {
if (modIndexes.at(i) == XKB_MOD_INVALID)
continue;
if (!(modMask & (1 << modIndexes.at(i))))
continue;
mods |= (1 << i);
}
return mods;
}
void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
if (!xkbState)
return;
xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group);
if (!updateModifiersState())
return;
keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed,
.latched = modifiersState.latched,
.locked = modifiersState.locked,
.group = modifiersState.group,
});
updateLEDs();
}
bool IKeyboard::updateModifiersState() {
if (!xkbState)
return false;
auto depressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED);
auto latched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
auto locked = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
auto group = xkb_state_serialize_layout(xkbState, XKB_STATE_LAYOUT_EFFECTIVE);
if (depressed == modifiersState.depressed && latched == modifiersState.latched && locked == modifiersState.locked && group == modifiersState.group)
return false;
modifiersState.depressed = depressed;
modifiersState.latched = latched;
modifiersState.locked = locked;
modifiersState.group = group;
return true;
}
void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
const auto contains = std::find(pressedXKB.begin(), pressedXKB.end(), xkbKey) != pressedXKB.end();
if (contains && pressed)
return;
if (!contains && !pressed)
return;
if (contains)
std::erase(pressedXKB, xkbKey);
else
pressedXKB.emplace_back(xkbKey);
xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
if (updateModifiersState()) {
keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed,
.latched = modifiersState.latched,
.locked = modifiersState.locked,
.group = modifiersState.group,
});
}
} }

View File

@@ -3,19 +3,31 @@
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp" #include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/Vector2D.hpp" #include "../helpers/math/Math.hpp"
#include <optional>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
struct wlr_keyboard; AQUAMARINE_FORWARD(IKeyboard);
enum eKeyboardModifiers {
HL_MODIFIER_SHIFT = (1 << 0),
HL_MODIFIER_CAPS = (1 << 1),
HL_MODIFIER_CTRL = (1 << 2),
HL_MODIFIER_ALT = (1 << 3),
HL_MODIFIER_MOD2 = (1 << 4),
HL_MODIFIER_MOD3 = (1 << 5),
HL_MODIFIER_META = (1 << 6),
HL_MODIFIER_MOD5 = (1 << 7),
};
class IKeyboard : public IHID { class IKeyboard : public IHID {
public: public:
virtual ~IKeyboard(); virtual ~IKeyboard();
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
virtual bool isVirtual() = 0; virtual bool isVirtual() = 0;
virtual wlr_keyboard* wlr() = 0; virtual SP<Aquamarine::IKeyboard> aq() = 0;
struct SKeyEvent { struct SKeyEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;
@@ -24,6 +36,17 @@ class IKeyboard : public IHID {
wl_keyboard_key_state state = WL_KEYBOARD_KEY_STATE_PRESSED; wl_keyboard_key_state state = WL_KEYBOARD_KEY_STATE_PRESSED;
}; };
struct SKeymapEvent {
xkb_keymap* keymap = nullptr;
};
struct SModifiersEvent {
uint32_t depressed = 0;
uint32_t latched = 0;
uint32_t locked = 0;
uint32_t group = 0;
};
struct { struct {
CSignal key; CSignal key;
CSignal modifiers; CSignal modifiers;
@@ -39,25 +62,53 @@ class IKeyboard : public IHID {
std::string rules = ""; std::string rules = "";
}; };
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); void setKeymap(const SStringRuleNames& rules);
std::string getActiveLayout(); void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
void updateLEDs(); std::string getActiveLayout();
void updateLEDs(uint32_t leds); std::optional<uint32_t> getLEDs();
void updateLEDs();
void updateLEDs(uint32_t leds);
uint32_t getModifiers();
void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
bool updateModifiersState(); // rets whether changed
void updateXkbStateWithKey(uint32_t xkbKey, bool pressed);
void updateKeymapFD();
bool active = false; bool active = false;
bool enabled = true; bool enabled = true;
xkb_layout_index_t activeLayout = 0; // if the keymap is overridden by the implementation,
xkb_state* xkbTranslationState = nullptr; // don't try to set keyboard rules anymore, to avoid overwriting the requested one.
// e.g. Virtual keyboards with custom maps.
bool keymapOverridden = false;
std::string hlName = ""; xkb_layout_index_t activeLayout = 0;
std::string xkbFilePath = ""; xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr;
xkb_keymap* xkbKeymap = nullptr;
SStringRuleNames currentRules; struct {
int repeatRate = 0; uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
int repeatDelay = 0; } modifiersState;
int numlockOn = -1;
bool resolveBindsBySym = false;
WP<IKeyboard> self; std::array<xkb_led_index_t, 3> ledIndexes = {XKB_MOD_INVALID};
std::array<xkb_mod_index_t, 8> modIndexes = {XKB_MOD_INVALID};
uint32_t leds = 0;
std::string hlName = "";
std::string xkbFilePath = "";
std::string xkbKeymapString = "";
int xkbKeymapFD = -1;
SStringRuleNames currentRules;
int repeatRate = 0;
int repeatDelay = 0;
int numlockOn = -1;
bool resolveBindsBySym = false;
WP<IKeyboard> self;
private:
void clearManuallyAllocd();
std::vector<uint32_t> pressedXKB;
}; };

View File

@@ -3,19 +3,19 @@
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp" #include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/Vector2D.hpp" #include "../helpers/math/Math.hpp"
struct wlr_pointer; AQUAMARINE_FORWARD(IPointer);
/* /*
Base class for a pointer. Base class for a pointer.
*/ */
class IPointer : public IHID { class IPointer : public IHID {
public: public:
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
virtual bool isVirtual() = 0; virtual bool isVirtual() = 0;
virtual wlr_pointer* wlr() = 0; virtual SP<Aquamarine::IPointer> aq() = 0;
struct SMotionEvent { struct SMotionEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;
@@ -106,7 +106,8 @@ class IPointer : public IHID {
} pointerEvents; } pointerEvents;
std::string hlName; std::string hlName;
bool connected = false; // means connected to the cursor bool connected = false; // means connected to the cursor
std::string boundOutput = "";
WP<IPointer> self; WP<IPointer> self;
}; };

View File

@@ -3,16 +3,16 @@
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp" #include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/Vector2D.hpp" #include "../helpers/math/Math.hpp"
struct wlr_touch; AQUAMARINE_FORWARD(ITouch);
class ITouch : public IHID { class ITouch : public IHID {
public: public:
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
virtual bool isVirtual() = 0; virtual bool isVirtual() = 0;
virtual wlr_touch* wlr() = 0; virtual SP<Aquamarine::ITouch> aq() = 0;
struct SDownEvent { struct SDownEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;

View File

@@ -1,7 +1,10 @@
#include "Keyboard.hpp" #include "Keyboard.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../Compositor.hpp"
SP<CKeyboard> CKeyboard::create(wlr_keyboard* keeb) { #include <aquamarine/input/Input.hpp>
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->self = pKeeb;
@@ -13,52 +16,41 @@ bool CKeyboard::isVirtual() {
return false; return false;
} }
wlr_keyboard* CKeyboard::wlr() { SP<Aquamarine::IKeyboard> CKeyboard::aq() {
return keyboard; return keyboard.lock();
} }
CKeyboard::CKeyboard(wlr_keyboard* keeb) : keyboard(keeb) { CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : keyboard(keeb) {
if (!keeb) if (!keeb)
return; return;
// clang-format off listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) { keyboard.reset();
disconnectCallbacks(); events.destroy.emit();
keyboard = nullptr; });
events.destroy.emit();
}, this, "CKeyboard");
hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) { listeners.key = keeb->events.key.registerListener([this](std::any d) {
auto E = (wlr_keyboard_key_event*)data; auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
keyboardEvents.key.emit(SKeyEvent{ keyboardEvents.key.emit(SKeyEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.keycode = E->keycode, .keycode = E.key,
.updateMods = E->update_state, .state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
.state = E->state,
}); });
}, this, "CKeyboard");
hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) { updateXkbStateWithKey(E.key + 8, E.pressed);
keyboardEvents.keymap.emit(); });
}, this, "CKeyboard");
hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) { listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
keyboardEvents.modifiers.emit(); updateModifiersState();
}, this, "CKeyboard");
hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) { keyboardEvents.modifiers.emit(SModifiersEvent{
keyboardEvents.repeatInfo.emit(); .depressed = modifiersState.depressed,
}, this, "CKeyboard"); .latched = modifiersState.latched,
// clang-format on .locked = modifiersState.locked,
.group = modifiersState.group,
});
});
deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN"; deviceName = keeb->getName();
}
void CKeyboard::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_key.removeCallback();
hyprListener_keymap.removeCallback();
hyprListener_repeatInfo.removeCallback();
hyprListener_modifiers.removeCallback();
} }

View File

@@ -4,21 +4,19 @@
class CKeyboard : public IKeyboard { class CKeyboard : public IKeyboard {
public: public:
static SP<CKeyboard> create(wlr_keyboard* keeb); static SP<CKeyboard> create(SP<Aquamarine::IKeyboard> keeb);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_keyboard* wlr(); virtual SP<Aquamarine::IKeyboard> aq();
private: private:
CKeyboard(wlr_keyboard* keeb); CKeyboard(SP<Aquamarine::IKeyboard> keeb);
wlr_keyboard* keyboard = nullptr; WP<Aquamarine::IKeyboard> keyboard;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener key;
DYNLISTENER(key); CHyprSignalListener modifiers;
DYNLISTENER(modifiers); } listeners;
DYNLISTENER(keymap);
DYNLISTENER(repeatInfo);
}; };

View File

@@ -1,7 +1,8 @@
#include "Mouse.hpp" #include "Mouse.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include <aquamarine/input/Input.hpp>
SP<CMouse> CMouse::create(wlr_pointer* 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->self = pMouse;
@@ -9,166 +10,143 @@ SP<CMouse> CMouse::create(wlr_pointer* mouse) {
return pMouse; return pMouse;
} }
CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) { CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
if (!mouse) if (!mouse)
return; return;
// clang-format off listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) { mouse.reset();
disconnectCallbacks();
mouse = nullptr;
events.destroy.emit(); events.destroy.emit();
}, this, "CMouse"); });
hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) { listeners.motion = mouse->events.move.registerListener([this](std::any d) {
auto E = (wlr_pointer_motion_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SMoveEvent>(d);
pointerEvents.motion.emit(SMotionEvent{ pointerEvents.motion.emit(SMotionEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.delta = {E->delta_x, E->delta_y}, .delta = E.delta,
.unaccel = {E->unaccel_dx, E->unaccel_dy}, .unaccel = E.unaccel,
}); });
}, this, "CMouse"); });
hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) { listeners.motionAbsolute = mouse->events.warp.registerListener([this](std::any d) {
auto E = (wlr_pointer_motion_absolute_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SWarpEvent>(d);
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.absolute = {E->x, E->y}, .absolute = E.absolute,
.device = self.lock(), .device = self.lock(),
}); });
}, this, "CMouse"); });
hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) { listeners.button = mouse->events.button.registerListener([this](std::any d) {
auto E = (wlr_pointer_button_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SButtonEvent>(d);
pointerEvents.button.emit(SButtonEvent{ pointerEvents.button.emit(SButtonEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.button = E->button, .button = E.button,
.state = (wl_pointer_button_state)E->state, .state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
}); });
}, this, "CMouse"); });
hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) { listeners.axis = mouse->events.axis.registerListener([this](std::any d) {
auto E = (wlr_pointer_axis_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SAxisEvent>(d);
pointerEvents.axis.emit(SAxisEvent{ pointerEvents.axis.emit(SAxisEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.source = E->source, .source = (wl_pointer_axis_source)E.source,
.axis = E->orientation, .axis = (wl_pointer_axis)E.axis,
.relativeDirection = E->relative_direction, .relativeDirection = (wl_pointer_axis_relative_direction)E.direction,
.delta = E->delta, .delta = E.delta,
.deltaDiscrete = E->delta_discrete, .deltaDiscrete = E.discrete,
}); });
}, this, "CMouse"); });
hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) { listeners.frame = mouse->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
pointerEvents.frame.emit();
}, this, "CMouse");
hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) { listeners.swipeBegin = mouse->events.swipeBegin.registerListener([this](std::any d) {
auto E = (wlr_pointer_swipe_begin_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SSwipeBeginEvent>(d);
pointerEvents.swipeBegin.emit(SSwipeBeginEvent{ pointerEvents.swipeBegin.emit(SSwipeBeginEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
}); });
}, this, "CMouse"); });
hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) { listeners.swipeEnd = mouse->events.swipeEnd.registerListener([this](std::any d) {
auto E = (wlr_pointer_swipe_end_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SSwipeEndEvent>(d);
pointerEvents.swipeEnd.emit(SSwipeEndEvent{ pointerEvents.swipeEnd.emit(SSwipeEndEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.cancelled = E->cancelled, .cancelled = E.cancelled,
}); });
}, this, "CMouse"); });
hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) { listeners.swipeUpdate = mouse->events.swipeUpdate.registerListener([this](std::any d) {
auto E = (wlr_pointer_swipe_update_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SSwipeUpdateEvent>(d);
pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{ pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
.delta = {E->dx, E->dy}, .delta = E.delta,
}); });
}, this, "CMouse"); });
hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) { listeners.pinchBegin = mouse->events.pinchBegin.registerListener([this](std::any d) {
auto E = (wlr_pointer_pinch_begin_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SPinchBeginEvent>(d);
pointerEvents.pinchBegin.emit(SPinchBeginEvent{ pointerEvents.pinchBegin.emit(SPinchBeginEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
}); });
}, this, "CMouse"); });
hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) { listeners.pinchEnd = mouse->events.pinchEnd.registerListener([this](std::any d) {
auto E = (wlr_pointer_pinch_end_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SPinchEndEvent>(d);
pointerEvents.pinchEnd.emit(SPinchEndEvent{ pointerEvents.pinchEnd.emit(SPinchEndEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.cancelled = E->cancelled, .cancelled = E.cancelled,
}); });
}, this, "CMouse"); });
hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) { listeners.pinchUpdate = mouse->events.pinchUpdate.registerListener([this](std::any d) {
auto E = (wlr_pointer_pinch_update_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SPinchUpdateEvent>(d);
pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{ pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
.delta = {E->dx, E->dy}, .delta = E.delta,
.scale = E->scale, .scale = E.scale,
.rotation = E->rotation, .rotation = E.rotation,
}); });
}, this, "CMouse"); });
hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) { listeners.holdBegin = mouse->events.holdBegin.registerListener([this](std::any d) {
auto E = (wlr_pointer_hold_begin_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SHoldBeginEvent>(d);
pointerEvents.holdBegin.emit(SHoldBeginEvent{ pointerEvents.holdBegin.emit(SHoldBeginEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.fingers = E->fingers, .fingers = E.fingers,
}); });
}, this, "CMouse"); });
hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) { listeners.holdEnd = mouse->events.holdEnd.registerListener([this](std::any d) {
auto E = (wlr_pointer_hold_end_event*)data; auto E = std::any_cast<Aquamarine::IPointer::SHoldEndEvent>(d);
pointerEvents.holdEnd.emit(SHoldEndEvent{ pointerEvents.holdEnd.emit(SHoldEndEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.cancelled = E->cancelled, .cancelled = E.cancelled,
}); });
}, this, "CMouse"); });
// clang-format on deviceName = mouse->getName();
deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN";
}
void CMouse::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_motion.removeCallback();
hyprListener_motionAbsolute.removeCallback();
hyprListener_button.removeCallback();
hyprListener_axis.removeCallback();
hyprListener_frame.removeCallback();
hyprListener_swipeBegin.removeCallback();
hyprListener_swipeEnd.removeCallback();
hyprListener_swipeUpdate.removeCallback();
hyprListener_pinchBegin.removeCallback();
hyprListener_pinchEnd.removeCallback();
hyprListener_pinchUpdate.removeCallback();
hyprListener_holdBegin.removeCallback();
hyprListener_holdEnd.removeCallback();
} }
bool CMouse::isVirtual() { bool CMouse::isVirtual() {
return false; return false;
} }
wlr_pointer* CMouse::wlr() { SP<Aquamarine::IPointer> CMouse::aq() {
return mouse; return mouse.lock();
} }

View File

@@ -4,33 +4,34 @@
class CMouse : public IPointer { class CMouse : public IPointer {
public: public:
static SP<CMouse> create(wlr_pointer* mouse); static SP<CMouse> create(SP<Aquamarine::IPointer> mouse);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_pointer* wlr(); virtual SP<Aquamarine::IPointer> aq();
private: private:
CMouse(wlr_pointer* mouse); CMouse(SP<Aquamarine::IPointer> mouse);
wlr_pointer* mouse = nullptr; WP<Aquamarine::IPointer> mouse;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener motion;
DYNLISTENER(motion); CHyprSignalListener motionAbsolute;
DYNLISTENER(motionAbsolute); CHyprSignalListener button;
DYNLISTENER(button); CHyprSignalListener axis;
DYNLISTENER(axis); CHyprSignalListener frame;
DYNLISTENER(frame);
DYNLISTENER(swipeBegin); CHyprSignalListener swipeBegin;
DYNLISTENER(swipeEnd); CHyprSignalListener swipeEnd;
DYNLISTENER(swipeUpdate); CHyprSignalListener swipeUpdate;
DYNLISTENER(pinchBegin); CHyprSignalListener pinchBegin;
DYNLISTENER(pinchEnd); CHyprSignalListener pinchEnd;
DYNLISTENER(pinchUpdate); CHyprSignalListener pinchUpdate;
DYNLISTENER(holdBegin); CHyprSignalListener holdBegin;
DYNLISTENER(holdEnd); CHyprSignalListener holdEnd;
} listeners;
}; };

View File

@@ -2,8 +2,9 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../protocols/Tablet.hpp" #include "../protocols/Tablet.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include <aquamarine/input/Input.hpp>
SP<CTablet> CTablet::create(wlr_tablet* 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->self = pTab;
@@ -13,7 +14,7 @@ SP<CTablet> CTablet::create(wlr_tablet* tablet) {
return pTab; return pTab;
} }
SP<CTabletTool> CTabletTool::create(wlr_tablet_tool* 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->self = pTab;
@@ -23,7 +24,7 @@ SP<CTabletTool> CTabletTool::create(wlr_tablet_tool* tablet) {
return pTab; return pTab;
} }
SP<CTabletPad> CTabletPad::create(wlr_tablet_pad* 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->self = pTab;
@@ -33,33 +34,25 @@ SP<CTabletPad> CTabletPad::create(wlr_tablet_pad* tablet) {
return pTab; return pTab;
} }
SP<CTabletTool> CTabletTool::fromWlr(wlr_tablet_tool* tool) { static uint32_t aqUpdateToHl(uint32_t aq) {
return ((CTabletTool*)tool->data)->self.lock();
}
SP<CTablet> CTablet::fromWlr(wlr_tablet* tablet) {
return ((CTablet*)tablet->data)->self.lock();
}
static uint32_t wlrUpdateToHl(uint32_t wlr) {
uint32_t result = 0; uint32_t result = 0;
if (wlr & WLR_TABLET_TOOL_AXIS_X) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_X)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X;
if (wlr & WLR_TABLET_TOOL_AXIS_Y) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_Y)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y;
if (wlr & WLR_TABLET_TOOL_AXIS_DISTANCE) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_DISTANCE)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE;
if (wlr & WLR_TABLET_TOOL_AXIS_PRESSURE) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_PRESSURE)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE;
if (wlr & WLR_TABLET_TOOL_AXIS_TILT_X) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_TILT_X)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X;
if (wlr & WLR_TABLET_TOOL_AXIS_TILT_Y) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_TILT_Y)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y;
if (wlr & WLR_TABLET_TOOL_AXIS_ROTATION) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_ROTATION)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION;
if (wlr & WLR_TABLET_TOOL_AXIS_SLIDER) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_SLIDER)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER;
if (wlr & WLR_TABLET_TOOL_AXIS_WHEEL) if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_WHEEL)
result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL; result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL;
return result; return result;
} }
@@ -68,97 +61,81 @@ uint32_t CTablet::getCapabilities() {
return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET;
} }
wlr_tablet* CTablet::wlr() { SP<Aquamarine::ITablet> CTablet::aq() {
return tablet; return tablet.lock();
} }
CTablet::CTablet(wlr_tablet* tablet_) : tablet(tablet_) { CTablet::CTablet(SP<Aquamarine::ITablet> tablet_) : tablet(tablet_) {
if (!tablet) if (!tablet)
return; return;
tablet->data = this; listeners.destroy = tablet->events.destroy.registerListener([this](std::any d) {
tablet.reset();
// clang-format off
hyprListener_destroy.initCallback(&tablet->base.events.destroy, [this] (void* owner, void* data) {
tablet = nullptr;
disconnectCallbacks();
events.destroy.emit(); events.destroy.emit();
}, this, "CTablet"); });
hyprListener_axis.initCallback(&tablet->events.axis, [this] (void* owner, void* data) { listeners.axis = tablet->events.axis.registerListener([this](std::any d) {
auto E = (wlr_tablet_tool_axis_event*)data; auto E = std::any_cast<Aquamarine::ITablet::SAxisEvent>(d);
tabletEvents.axis.emit(SAxisEvent{ tabletEvents.axis.emit(SAxisEvent{
.tool = E->tool, .tool = E.tool,
.tablet = self.lock(), .tablet = self.lock(),
.timeMs = E->time_msec, .timeMs = E.timeMs,
.updatedAxes = wlrUpdateToHl(E->updated_axes), .updatedAxes = aqUpdateToHl(E.updatedAxes),
.axis = {E->x, E->y}, .axis = E.absolute,
.axisDelta = {E->dx, E->dy}, .axisDelta = E.delta,
.tilt = {E->tilt_x, E->tilt_y}, .tilt = E.tilt,
.pressure = E->pressure, .pressure = E.pressure,
.distance = E->distance, .distance = E.distance,
.rotation = E->rotation, .rotation = E.rotation,
.slider = E->slider, .slider = E.slider,
.wheelDelta = E->wheel_delta, .wheelDelta = E.wheelDelta,
}); });
}, this, "CTablet"); });
hyprListener_proximity.initCallback(&tablet->events.proximity, [this] (void* owner, void* data) { listeners.proximity = tablet->events.proximity.registerListener([this](std::any d) {
auto E = (wlr_tablet_tool_proximity_event*)data; auto E = std::any_cast<Aquamarine::ITablet::SProximityEvent>(d);
tabletEvents.proximity.emit(SProximityEvent{ tabletEvents.proximity.emit(SProximityEvent{
.tool = E->tool, .tool = E.tool,
.tablet = self.lock(), .tablet = self.lock(),
.timeMs = E->time_msec, .timeMs = E.timeMs,
.proximity = {E->x, E->y}, .proximity = E.absolute,
.in = E->state == WLR_TABLET_TOOL_PROXIMITY_IN, .in = E.in,
}); });
}, this, "CTablet"); });
hyprListener_tip.initCallback(&tablet->events.tip, [this] (void* owner, void* data) { listeners.tip = tablet->events.tip.registerListener([this](std::any d) {
auto E = (wlr_tablet_tool_tip_event*)data; auto E = std::any_cast<Aquamarine::ITablet::STipEvent>(d);
tabletEvents.tip.emit(STipEvent{ tabletEvents.tip.emit(STipEvent{
.tool = E->tool, .tool = E.tool,
.tablet = self.lock(), .tablet = self.lock(),
.timeMs = E->time_msec, .timeMs = E.timeMs,
.tip = {E->x, E->y}, .tip = E.absolute,
.in = E->state == WLR_TABLET_TOOL_TIP_DOWN, .in = E.down,
}); });
}, this, "CTablet"); });
hyprListener_button.initCallback(&tablet->events.button, [this] (void* owner, void* data) { listeners.button = tablet->events.button.registerListener([this](std::any d) {
auto E = (wlr_tablet_tool_button_event*)data; auto E = std::any_cast<Aquamarine::ITablet::SButtonEvent>(d);
tabletEvents.button.emit(SButtonEvent{ tabletEvents.button.emit(SButtonEvent{
.tool = E->tool, .tool = E.tool,
.tablet = self.lock(), .tablet = self.lock(),
.timeMs = E->time_msec, .timeMs = E.timeMs,
.button = E->button, .button = E.button,
.down = E->state == WLR_BUTTON_PRESSED, .down = E.down,
}); });
}, this, "CTablet"); });
// clang-format on
deviceName = tablet->base.name ? tablet->base.name : "UNKNOWN"; deviceName = tablet->getName();
} }
CTablet::~CTablet() { CTablet::~CTablet() {
if (tablet)
tablet->data = nullptr;
PROTO::tablet->recheckRegisteredDevices(); PROTO::tablet->recheckRegisteredDevices();
} }
void CTablet::disconnectCallbacks() {
hyprListener_axis.removeCallback();
hyprListener_button.removeCallback();
hyprListener_destroy.removeCallback();
hyprListener_proximity.removeCallback();
hyprListener_tip.removeCallback();
}
eHIDType CTablet::getType() { eHIDType CTablet::getType() {
return HID_TYPE_TABLET; return HID_TYPE_TABLET;
} }
@@ -167,138 +144,111 @@ uint32_t CTabletPad::getCapabilities() {
return HID_INPUT_CAPABILITY_TABLET; return HID_INPUT_CAPABILITY_TABLET;
} }
wlr_tablet_pad* CTabletPad::wlr() { SP<Aquamarine::ITabletPad> CTabletPad::aq() {
return pad; return pad.lock();
} }
eHIDType CTabletPad::getType() { eHIDType CTabletPad::getType() {
return HID_TYPE_TABLET_PAD; return HID_TYPE_TABLET_PAD;
} }
CTabletPad::CTabletPad(wlr_tablet_pad* pad_) : pad(pad_) { CTabletPad::CTabletPad(SP<Aquamarine::ITabletPad> pad_) : pad(pad_) {
if (!pad) if (!pad)
return; return;
// clang-format off listeners.destroy = pad->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&pad->base.events.destroy, [this] (void* owner, void* data) { pad.reset();
pad = nullptr;
disconnectCallbacks();
events.destroy.emit(); events.destroy.emit();
}, this, "CTabletPad"); });
hyprListener_button.initCallback(&pad->events.button, [this] (void* owner, void* data) { listeners.button = pad->events.button.registerListener([this](std::any d) {
auto E = (wlr_tablet_pad_button_event*)data; auto E = std::any_cast<Aquamarine::ITabletPad::SButtonEvent>(d);
padEvents.button.emit(SButtonEvent{ padEvents.button.emit(SButtonEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.button = E->button, .button = E.button,
.down = E->state == WLR_BUTTON_PRESSED, .down = E.down,
.mode = E->mode, .mode = E.mode,
.group = E->group, .group = E.group,
}); });
}, this, "CTabletPad"); });
hyprListener_ring.initCallback(&pad->events.ring, [this] (void* owner, void* data) { listeners.ring = pad->events.ring.registerListener([this](std::any d) {
auto E = (wlr_tablet_pad_ring_event*)data; auto E = std::any_cast<Aquamarine::ITabletPad::SRingEvent>(d);
padEvents.ring.emit(SRingEvent{ padEvents.ring.emit(SRingEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.finger = E->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_RING_SOURCE_FINGER,
.ring = E->ring, .ring = E.ring,
.position = E->position, .position = E.pos,
.mode = E->mode, .mode = E.mode,
}); });
}, this, "CTabletPad"); });
hyprListener_strip.initCallback(&pad->events.strip, [this] (void* owner, void* data) { listeners.strip = pad->events.strip.registerListener([this](std::any d) {
auto E = (wlr_tablet_pad_strip_event*)data; auto E = std::any_cast<Aquamarine::ITabletPad::SStripEvent>(d);
padEvents.strip.emit(SStripEvent{ padEvents.strip.emit(SStripEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.finger = E->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_STRIP_SOURCE_FINGER,
.strip = E->strip, .strip = E.strip,
.position = E->position, .position = E.pos,
.mode = E->mode, .mode = E.mode,
}); });
}, this, "CTabletPad"); });
hyprListener_attach.initCallback(&pad->events.attach_tablet, [this] (void* owner, void* data) { listeners.attach = pad->events.attach.registerListener([this](std::any d) {
if (!data) ; // TODO: this doesn't do anything in aq atm
return; });
padEvents.attach.emit(CTabletTool::fromWlr((wlr_tablet_tool*)data));
}, this, "CTabletPad");
// clang-format on
deviceName = pad->base.name ? pad->base.name : "UNKNOWN"; deviceName = pad->getName();
} }
CTabletPad::~CTabletPad() { CTabletPad::~CTabletPad() {
PROTO::tablet->recheckRegisteredDevices(); PROTO::tablet->recheckRegisteredDevices();
} }
void CTabletPad::disconnectCallbacks() {
hyprListener_ring.removeCallback();
hyprListener_button.removeCallback();
hyprListener_destroy.removeCallback();
hyprListener_strip.removeCallback();
hyprListener_attach.removeCallback();
}
uint32_t CTabletTool::getCapabilities() { uint32_t CTabletTool::getCapabilities() {
return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET;
} }
wlr_tablet_tool* CTabletTool::wlr() { SP<Aquamarine::ITabletTool> CTabletTool::aq() {
return tool; return tool.lock();
} }
eHIDType CTabletTool::getType() { eHIDType CTabletTool::getType() {
return HID_TYPE_TABLET_TOOL; return HID_TYPE_TABLET_TOOL;
} }
CTabletTool::CTabletTool(wlr_tablet_tool* tool_) : tool(tool_) { CTabletTool::CTabletTool(SP<Aquamarine::ITabletTool> tool_) : tool(tool_) {
if (!tool) if (!tool)
return; return;
// clang-format off listeners.destroyTool = tool->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&tool->events.destroy, [this] (void* owner, void* data) { tool.reset();
tool = nullptr;
disconnectCallbacks();
events.destroy.emit(); events.destroy.emit();
}, this, "CTabletTool"); });
// clang-format on
if (tool->tilt) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_TILT)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT;
if (tool->pressure) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_PRESSURE)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE;
if (tool->distance) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_DISTANCE)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE;
if (tool->rotation) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_ROTATION)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION;
if (tool->slider) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_SLIDER)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER;
if (tool->wheel) if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_WHEEL)
toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL; toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL;
tool->data = this; deviceName = std::format("{:x}-{:x}", tool->serial, tool->id);
deviceName = std::to_string(tool->hardware_serial) + std::to_string(tool->hardware_wacom);
} }
CTabletTool::~CTabletTool() { CTabletTool::~CTabletTool() {
if (tool)
tool->data = nullptr;
PROTO::tablet->recheckRegisteredDevices(); PROTO::tablet->recheckRegisteredDevices();
} }
void CTabletTool::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
listeners.destroySurface.reset();
}
SP<CWLSurfaceResource> CTabletTool::getSurface() { SP<CWLSurfaceResource> CTabletTool::getSurface() {
return pSurface.lock(); return pSurface.lock();
} }

View File

@@ -3,12 +3,12 @@
#include "IHID.hpp" #include "IHID.hpp"
#include "../helpers/WLListener.hpp" #include "../helpers/WLListener.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../helpers/Vector2D.hpp" #include "../helpers/math/Math.hpp"
#include "../helpers/Box.hpp" #include "../helpers/math/Math.hpp"
struct wlr_tablet; AQUAMARINE_FORWARD(ITablet);
struct wlr_tablet_tool; AQUAMARINE_FORWARD(ITabletTool);
struct wlr_tablet_pad; AQUAMARINE_FORWARD(ITabletPad);
class CTabletTool; class CTabletTool;
class CTabletPad; class CTabletPad;
@@ -21,13 +21,12 @@ class CWLSurfaceResource;
*/ */
class CTablet : public IHID { class CTablet : public IHID {
public: public:
static SP<CTablet> create(wlr_tablet* tablet); static SP<CTablet> create(SP<Aquamarine::ITablet> tablet);
static SP<CTablet> fromWlr(wlr_tablet* tablet);
~CTablet(); ~CTablet();
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
wlr_tablet* wlr(); SP<Aquamarine::ITablet> aq();
enum eTabletToolAxes { enum eTabletToolAxes {
HID_TABLET_TOOL_AXIS_X = (1 << 0), HID_TABLET_TOOL_AXIS_X = (1 << 0),
@@ -42,46 +41,46 @@ class CTablet : public IHID {
}; };
struct SAxisEvent { struct SAxisEvent {
wlr_tablet_tool* tool; SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet; SP<CTablet> tablet;
uint32_t timeMs = 0; uint32_t timeMs = 0;
uint32_t updatedAxes = 0; // eTabletToolAxes uint32_t updatedAxes = 0; // eTabletToolAxes
Vector2D axis; Vector2D axis;
Vector2D axisDelta; Vector2D axisDelta;
Vector2D tilt; Vector2D tilt;
double pressure = 0; double pressure = 0;
double distance = 0; double distance = 0;
double rotation = 0; double rotation = 0;
double slider = 0; double slider = 0;
double wheelDelta = 0; double wheelDelta = 0;
}; };
struct SProximityEvent { struct SProximityEvent {
wlr_tablet_tool* tool; SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet; SP<CTablet> tablet;
uint32_t timeMs = 0; uint32_t timeMs = 0;
Vector2D proximity; Vector2D proximity;
bool in = false; bool in = false;
}; };
struct STipEvent { struct STipEvent {
wlr_tablet_tool* tool; SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet; SP<CTablet> tablet;
uint32_t timeMs = 0; uint32_t timeMs = 0;
Vector2D tip; Vector2D tip;
bool in = false; bool in = false;
}; };
struct SButtonEvent { struct SButtonEvent {
wlr_tablet_tool* tool; SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet; SP<CTablet> tablet;
uint32_t timeMs = 0; uint32_t timeMs = 0;
uint32_t button; uint32_t button;
bool down = false; bool down = false;
}; };
struct { struct {
@@ -100,27 +99,27 @@ class CTablet : public IHID {
CBox boundBox; // output-local CBox boundBox; // output-local
private: private:
CTablet(wlr_tablet* tablet); CTablet(SP<Aquamarine::ITablet> tablet);
void disconnectCallbacks(); WP<Aquamarine::ITablet> tablet;
wlr_tablet* tablet = nullptr; struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener axis;
DYNLISTENER(axis); CHyprSignalListener proximity;
DYNLISTENER(proximity); CHyprSignalListener tip;
DYNLISTENER(tip); CHyprSignalListener button;
DYNLISTENER(button); } listeners;
}; };
class CTabletPad : public IHID { class CTabletPad : public IHID {
public: public:
static SP<CTabletPad> create(wlr_tablet_pad* pad); static SP<CTabletPad> create(SP<Aquamarine::ITabletPad> pad);
~CTabletPad(); ~CTabletPad();
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
virtual eHIDType getType(); virtual eHIDType getType();
wlr_tablet_pad* wlr(); SP<Aquamarine::ITabletPad> aq();
struct SButtonEvent { struct SButtonEvent {
uint32_t timeMs = 0; uint32_t timeMs = 0;
@@ -159,23 +158,22 @@ class CTabletPad : public IHID {
std::string hlName; std::string hlName;
private: private:
CTabletPad(wlr_tablet_pad* pad); CTabletPad(SP<Aquamarine::ITabletPad> pad);
void disconnectCallbacks(); WP<Aquamarine::ITabletPad> pad;
wlr_tablet_pad* pad = nullptr; struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener ring;
DYNLISTENER(ring); CHyprSignalListener strip;
DYNLISTENER(strip); CHyprSignalListener button;
DYNLISTENER(button); CHyprSignalListener attach;
DYNLISTENER(attach); } listeners;
}; };
class CTabletTool : public IHID { class CTabletTool : public IHID {
public: public:
static SP<CTabletTool> create(wlr_tablet_tool* tool); static SP<CTabletTool> create(SP<Aquamarine::ITabletTool> tool);
static SP<CTabletTool> fromWlr(wlr_tablet_tool* tool);
~CTabletTool(); ~CTabletTool();
enum eTabletToolType { enum eTabletToolType {
@@ -198,35 +196,31 @@ class CTabletTool : public IHID {
HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5), HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5),
}; };
virtual uint32_t getCapabilities(); virtual uint32_t getCapabilities();
wlr_tablet_tool* wlr(); SP<Aquamarine::ITabletTool> aq();
virtual eHIDType getType(); virtual eHIDType getType();
SP<CWLSurfaceResource> getSurface(); SP<CWLSurfaceResource> getSurface();
void setSurface(SP<CWLSurfaceResource>); void setSurface(SP<CWLSurfaceResource>);
WP<CTabletTool> self; WP<CTabletTool> self;
Vector2D tilt; Vector2D tilt;
bool active = false; // true if in proximity bool active = false; // true if in proximity
uint32_t toolCapabilities = 0; uint32_t toolCapabilities = 0;
bool isDown = false; bool isDown = false;
std::vector<uint32_t> buttonsDown; std::vector<uint32_t> buttonsDown;
Vector2D absolutePos; // last known absolute position. Vector2D absolutePos; // last known absolute position.
std::string hlName; std::string hlName;
private: private:
CTabletTool(wlr_tablet_tool* tool); CTabletTool(SP<Aquamarine::ITabletTool> tool);
void disconnectCallbacks(); WP<CWLSurfaceResource> pSurface;
WP<Aquamarine::ITabletTool> tool;
WP<CWLSurfaceResource> pSurface;
wlr_tablet_tool* tool = nullptr;
DYNLISTENER(destroy);
struct { struct {
CHyprSignalListener destroySurface; CHyprSignalListener destroySurface;
CHyprSignalListener destroyTool;
} listeners; } listeners;
}; };

View File

@@ -1,7 +1,8 @@
#include "TouchDevice.hpp" #include "TouchDevice.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include <aquamarine/input/Input.hpp>
SP<CTouchDevice> CTouchDevice::create(wlr_touch* 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->self = pTouch;
@@ -9,78 +10,63 @@ SP<CTouchDevice> CTouchDevice::create(wlr_touch* touch) {
return pTouch; return pTouch;
} }
CTouchDevice::CTouchDevice(wlr_touch* touch_) : touch(touch_) { CTouchDevice::CTouchDevice(SP<Aquamarine::ITouch> touch_) : touch(touch_) {
if (!touch) if (!touch)
return; return;
// clang-format off listeners.destroy = touch->events.destroy.registerListener([this](std::any d) {
hyprListener_destroy.initCallback(&touch->base.events.destroy, [this] (void* owner, void* data) {
events.destroy.emit(); events.destroy.emit();
disconnectCallbacks(); touch.reset();
touch = nullptr; });
}, this, "CTouchDevice");
hyprListener_down.initCallback(&touch->events.down, [this] (void* owner, void* data) { listeners.down = touch->events.down.registerListener([this](std::any d) {
auto E = (wlr_touch_down_event*)data; auto E = std::any_cast<Aquamarine::ITouch::SDownEvent>(d);
touchEvents.down.emit(SDownEvent{ touchEvents.down.emit(SDownEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.touchID = E->touch_id, .touchID = E.touchID,
.pos = {E->x, E->y}, .pos = E.pos,
.device = self.lock(), .device = self.lock(),
}); });
}, this, "CTouchDevice"); });
hyprListener_up.initCallback(&touch->events.up, [this] (void* owner, void* data) { listeners.up = touch->events.up.registerListener([this](std::any d) {
auto E = (wlr_touch_up_event*)data; auto E = std::any_cast<Aquamarine::ITouch::SUpEvent>(d);
touchEvents.up.emit(SUpEvent{ touchEvents.up.emit(SUpEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.touchID = E->touch_id .touchID = E.touchID,
}); });
}, this, "CTouchDevice"); });
hyprListener_motion.initCallback(&touch->events.motion, [this] (void* owner, void* data) { listeners.motion = touch->events.move.registerListener([this](std::any d) {
auto E = (wlr_touch_motion_event*)data; auto E = std::any_cast<Aquamarine::ITouch::SMotionEvent>(d);
touchEvents.motion.emit(SMotionEvent{ touchEvents.motion.emit(SMotionEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.touchID = E->touch_id, .touchID = E.touchID,
.pos = {E->x, E->y}, .pos = E.pos,
}); });
}, this, "CTouchDevice"); });
hyprListener_cancel.initCallback(&touch->events.cancel, [this] (void* owner, void* data) { listeners.cancel = touch->events.cancel.registerListener([this](std::any d) {
auto E = (wlr_touch_cancel_event*)data; auto E = std::any_cast<Aquamarine::ITouch::SCancelEvent>(d);
touchEvents.cancel.emit(SCancelEvent{ touchEvents.cancel.emit(SCancelEvent{
.timeMs = E->time_msec, .timeMs = E.timeMs,
.touchID = E->touch_id .touchID = E.touchID,
}); });
}, this, "CTouchDevice"); });
hyprListener_frame.initCallback(&touch->events.frame, [this] (void* owner, void* data) { listeners.frame = touch->events.frame.registerListener([this](std::any d) { touchEvents.frame.emit(); });
touchEvents.frame.emit();
}, this, "CTouchDevice");
// clang-format on deviceName = touch->getName();
deviceName = touch->base.name ? touch->base.name : "UNKNOWN";
} }
bool CTouchDevice::isVirtual() { bool CTouchDevice::isVirtual() {
return false; return false;
} }
wlr_touch* CTouchDevice::wlr() { SP<Aquamarine::ITouch> CTouchDevice::aq() {
return touch; return touch.lock();
}
void CTouchDevice::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_down.removeCallback();
hyprListener_up.removeCallback();
hyprListener_motion.removeCallback();
hyprListener_cancel.removeCallback();
hyprListener_frame.removeCallback();
} }

View File

@@ -4,22 +4,22 @@
class CTouchDevice : public ITouch { class CTouchDevice : public ITouch {
public: public:
static SP<CTouchDevice> create(wlr_touch* touch); static SP<CTouchDevice> create(SP<Aquamarine::ITouch> touch);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_touch* wlr(); virtual SP<Aquamarine::ITouch> aq();
private: private:
CTouchDevice(wlr_touch* touch); CTouchDevice(SP<Aquamarine::ITouch> touch);
wlr_touch* touch = nullptr; WP<Aquamarine::ITouch> touch;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener down;
DYNLISTENER(down); CHyprSignalListener up;
DYNLISTENER(up); CHyprSignalListener motion;
DYNLISTENER(motion); CHyprSignalListener cancel;
DYNLISTENER(cancel); CHyprSignalListener frame;
DYNLISTENER(frame); } listeners;
}; };

View File

@@ -14,58 +14,42 @@ CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : keybo
if (!keeb_) if (!keeb_)
return; return;
auto keeb = keeb_->wlr(); listeners.destroy = keeb_->events.destroy.registerListener([this](std::any d) {
// clang-format off
hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) {
disconnectCallbacks();
keyboard.reset(); keyboard.reset();
events.destroy.emit(); events.destroy.emit();
}, this, "CVirtualKeyboard"); });
hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) { listeners.key = keeb_->events.key.registerListener([this](std::any d) { keyboardEvents.key.emit(d); });
auto E = (wlr_keyboard_key_event*)data; listeners.modifiers = keeb_->events.modifiers.registerListener([this](std::any d) {
auto E = std::any_cast<SModifiersEvent>(d);
keyboardEvents.key.emit(SKeyEvent{ updateModifiers(E.depressed, E.latched, E.locked, E.group);
.timeMs = E->time_msec, keyboardEvents.modifiers.emit(SModifiersEvent{
.keycode = E->keycode, .depressed = modifiersState.depressed,
.updateMods = E->update_state, .latched = modifiersState.latched,
.state = E->state, .locked = modifiersState.locked,
.group = modifiersState.group,
}); });
}, this, "CVirtualKeyboard"); });
listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) {
auto E = std::any_cast<SKeymapEvent>(d);
if (xkbKeymap)
xkb_keymap_unref(xkbKeymap);
xkbKeymap = xkb_keymap_ref(E.keymap);
keymapOverridden = true;
updateXKBTranslationState(xkbKeymap);
updateKeymapFD();
keyboardEvents.keymap.emit(d);
});
hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) { deviceName = keeb_->name;
keyboardEvents.keymap.emit();
}, this, "CVirtualKeyboard");
hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) {
keyboardEvents.modifiers.emit();
}, this, "CVirtualKeyboard");
hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) {
keyboardEvents.repeatInfo.emit();
}, this, "CVirtualKeyboard");
// clang-format on
deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN";
} }
bool CVirtualKeyboard::isVirtual() { bool CVirtualKeyboard::isVirtual() {
return true; return true;
} }
wlr_keyboard* CVirtualKeyboard::wlr() { SP<Aquamarine::IKeyboard> CVirtualKeyboard::aq() {
if (keyboard.expired()) return nullptr;
return nullptr;
return keyboard->wlr();
}
void CVirtualKeyboard::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_key.removeCallback();
hyprListener_keymap.removeCallback();
hyprListener_repeatInfo.removeCallback();
hyprListener_modifiers.removeCallback();
} }
wl_client* CVirtualKeyboard::getClient() { wl_client* CVirtualKeyboard::getClient() {

View File

@@ -6,23 +6,22 @@ class CVirtualKeyboardV1Resource;
class CVirtualKeyboard : public IKeyboard { class CVirtualKeyboard : public IKeyboard {
public: public:
static SP<CVirtualKeyboard> create(SP<CVirtualKeyboardV1Resource> keeb); static SP<CVirtualKeyboard> create(SP<CVirtualKeyboardV1Resource> keeb);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_keyboard* wlr(); virtual SP<Aquamarine::IKeyboard> aq();
wl_client* getClient(); wl_client* getClient();
private: private:
CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb); CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb);
WP<CVirtualKeyboardV1Resource> keyboard; WP<CVirtualKeyboardV1Resource> keyboard;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener key;
DYNLISTENER(key); CHyprSignalListener modifiers;
DYNLISTENER(modifiers); CHyprSignalListener keymap;
DYNLISTENER(keymap); } listeners;
DYNLISTENER(repeatInfo);
}; };

View File

@@ -1,5 +1,6 @@
#include "VirtualPointer.hpp" #include "VirtualPointer.hpp"
#include "../protocols/VirtualPointer.hpp" #include "../protocols/VirtualPointer.hpp"
#include <aquamarine/input/Input.hpp>
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));
@@ -13,165 +14,39 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
if (!resource->good()) if (!resource->good())
return; return;
auto mouse = resource->wlr(); listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) {
pointer.reset();
// clang-format off
hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) {
disconnectCallbacks();
events.destroy.emit(); events.destroy.emit();
}, this, "CVirtualPointer"); });
hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) { listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
auto E = (wlr_pointer_motion_event*)data; listeners.motionAbsolute = pointer->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
auto E = std::any_cast<SMotionAbsoluteEvent>(d);
E.device = self.lock();
pointerEvents.motionAbsolute.emit(E);
});
listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); });
listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); });
listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
listeners.swipeBegin = pointer->events.swipeBegin.registerListener([this](std::any d) { pointerEvents.swipeBegin.emit(d); });
listeners.swipeEnd = pointer->events.swipeEnd.registerListener([this](std::any d) { pointerEvents.swipeEnd.emit(d); });
listeners.swipeUpdate = pointer->events.swipeUpdate.registerListener([this](std::any d) { pointerEvents.swipeUpdate.emit(d); });
listeners.pinchBegin = pointer->events.pinchBegin.registerListener([this](std::any d) { pointerEvents.pinchBegin.emit(d); });
listeners.pinchEnd = pointer->events.pinchEnd.registerListener([this](std::any d) { pointerEvents.pinchEnd.emit(d); });
listeners.pinchUpdate = pointer->events.pinchUpdate.registerListener([this](std::any d) { pointerEvents.pinchUpdate.emit(d); });
listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); });
listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); });
pointerEvents.motion.emit(SMotionEvent{ boundOutput = resource->boundOutput ? resource->boundOutput->szName : "entire";
.timeMs = E->time_msec,
.delta = {E->delta_x, E->delta_y},
.unaccel = {E->unaccel_dx, E->unaccel_dy},
});
}, this, "CVirtualPointer");
hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) { deviceName = pointer->name;
auto E = (wlr_pointer_motion_absolute_event*)data;
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E->time_msec,
.absolute = {E->x, E->y},
.device = self.lock(),
});
}, this, "CVirtualPointer");
hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) {
auto E = (wlr_pointer_button_event*)data;
pointerEvents.button.emit(SButtonEvent{
.timeMs = E->time_msec,
.button = E->button,
.state = (wl_pointer_button_state)E->state,
});
}, this, "CVirtualPointer");
hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) {
auto E = (wlr_pointer_axis_event*)data;
pointerEvents.axis.emit(SAxisEvent{
.timeMs = E->time_msec,
.source = E->source,
.axis = E->orientation,
.relativeDirection = E->relative_direction,
.delta = E->delta,
.deltaDiscrete = E->delta_discrete,
});
}, this, "CVirtualPointer");
hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) {
pointerEvents.frame.emit();
}, this, "CVirtualPointer");
hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_begin_event*)data;
pointerEvents.swipeBegin.emit(SSwipeBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
});
}, this, "CVirtualPointer");
hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_end_event*)data;
pointerEvents.swipeEnd.emit(SSwipeEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
});
}, this, "CVirtualPointer");
hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_update_event*)data;
pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.delta = {E->dx, E->dy},
});
}, this, "CVirtualPointer");
hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_begin_event*)data;
pointerEvents.pinchBegin.emit(SPinchBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
});
}, this, "CVirtualPointer");
hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_end_event*)data;
pointerEvents.pinchEnd.emit(SPinchEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
});
}, this, "CVirtualPointer");
hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_update_event*)data;
pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.delta = {E->dx, E->dy},
.scale = E->scale,
.rotation = E->rotation,
});
}, this, "CVirtualPointer");
hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_hold_begin_event*)data;
pointerEvents.holdBegin.emit(SHoldBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
});
}, this, "CVirtualPointer");
hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_hold_end_event*)data;
pointerEvents.holdEnd.emit(SHoldEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
});
}, this, "CVirtualPointer");
// clang-format on
deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN";
} }
bool CVirtualPointer::isVirtual() { bool CVirtualPointer::isVirtual() {
return true; return true;
} }
void CVirtualPointer::disconnectCallbacks() { SP<Aquamarine::IPointer> CVirtualPointer::aq() {
hyprListener_destroy.removeCallback(); return nullptr;
hyprListener_motion.removeCallback();
hyprListener_motionAbsolute.removeCallback();
hyprListener_button.removeCallback();
hyprListener_axis.removeCallback();
hyprListener_frame.removeCallback();
hyprListener_swipeBegin.removeCallback();
hyprListener_swipeEnd.removeCallback();
hyprListener_swipeUpdate.removeCallback();
hyprListener_pinchBegin.removeCallback();
hyprListener_pinchEnd.removeCallback();
hyprListener_pinchUpdate.removeCallback();
hyprListener_holdBegin.removeCallback();
hyprListener_holdEnd.removeCallback();
}
wlr_pointer* CVirtualPointer::wlr() {
if (pointer.expired())
return nullptr;
return pointer->wlr();
} }

View File

@@ -6,33 +6,34 @@ class CVirtualPointerV1Resource;
class CVirtualPointer : public IPointer { class CVirtualPointer : public IPointer {
public: public:
static SP<CVirtualPointer> create(SP<CVirtualPointerV1Resource> resource); static SP<CVirtualPointer> create(SP<CVirtualPointerV1Resource> resource);
virtual bool isVirtual(); virtual bool isVirtual();
virtual wlr_pointer* wlr(); virtual SP<Aquamarine::IPointer> aq();
private: private:
CVirtualPointer(SP<CVirtualPointerV1Resource>); CVirtualPointer(SP<CVirtualPointerV1Resource>);
WP<CVirtualPointerV1Resource> pointer; WP<CVirtualPointerV1Resource> pointer;
void disconnectCallbacks(); struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy); CHyprSignalListener motion;
DYNLISTENER(motion); CHyprSignalListener motionAbsolute;
DYNLISTENER(motionAbsolute); CHyprSignalListener button;
DYNLISTENER(button); CHyprSignalListener axis;
DYNLISTENER(axis); CHyprSignalListener frame;
DYNLISTENER(frame);
DYNLISTENER(swipeBegin); CHyprSignalListener swipeBegin;
DYNLISTENER(swipeEnd); CHyprSignalListener swipeEnd;
DYNLISTENER(swipeUpdate); CHyprSignalListener swipeUpdate;
DYNLISTENER(pinchBegin); CHyprSignalListener pinchBegin;
DYNLISTENER(pinchEnd); CHyprSignalListener pinchEnd;
DYNLISTENER(pinchUpdate); CHyprSignalListener pinchUpdate;
DYNLISTENER(holdBegin); CHyprSignalListener holdBegin;
DYNLISTENER(holdEnd); CHyprSignalListener holdEnd;
} listeners;
}; };

View File

@@ -1,50 +0,0 @@
#include "Events.hpp"
#include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
// ---------------------------------------------------- //
// _____ ________ _______ _____ ______ _____ //
// | __ \| ____\ \ / /_ _/ ____| ____|/ ____| //
// | | | | |__ \ \ / / | || | | |__ | (___ //
// | | | | __| \ \/ / | || | | __| \___ \ //
// | |__| | |____ \ / _| || |____| |____ ____) | //
// |_____/|______| \/ |_____\_____|______|_____/ //
// //
// ---------------------------------------------------- //
void Events::listener_newInput(wl_listener* listener, void* data) {
const auto DEVICE = (wlr_input_device*)data;
switch (DEVICE->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
Debug::log(LOG, "Attached a keyboard with name {}", DEVICE->name);
g_pInputManager->newKeyboard(DEVICE);
break;
case WLR_INPUT_DEVICE_POINTER:
Debug::log(LOG, "Attached a mouse with name {}", DEVICE->name);
g_pInputManager->newMouse(DEVICE);
break;
case WLR_INPUT_DEVICE_TOUCH:
Debug::log(LOG, "Attached a touch device with name {}", DEVICE->name);
g_pInputManager->newTouchDevice(DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET:
Debug::log(LOG, "Attached a tablet with name {}", DEVICE->name);
g_pInputManager->newTablet(DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET_PAD:
Debug::log(LOG, "Attached a tablet pad with name {}", DEVICE->name);
g_pInputManager->newTabletPad(DEVICE);
break;
case WLR_INPUT_DEVICE_SWITCH:
Debug::log(LOG, "Attached a switch device with name {}", DEVICE->name);
g_pInputManager->newSwitch(DEVICE);
break;
default: Debug::log(WARN, "Unrecognized input device plugged in: {}", DEVICE->name); break;
}
g_pInputManager->updateCapabilities();
}

View File

@@ -8,16 +8,6 @@
// //
namespace Events { namespace Events {
// Monitor events
LISTENER(change);
LISTENER(newOutput);
// DRM events
LISTENER(leaseRequest);
// Layer events
LISTENER(newLayerSurface);
// Window events // Window events
DYNLISTENFUNC(commitWindow); DYNLISTENFUNC(commitWindow);
DYNLISTENFUNC(mapWindow); DYNLISTENFUNC(mapWindow);
@@ -35,15 +25,6 @@ namespace Events {
DYNLISTENFUNC(setOverrideRedirect); DYNLISTENFUNC(setOverrideRedirect);
DYNLISTENFUNC(ackConfigure); DYNLISTENFUNC(ackConfigure);
LISTENER(newInput);
// Virt Ptr
LISTENER(newVirtPtr);
// Various
LISTENER(requestSetSel);
LISTENER(requestSetPrimarySel);
// Monitor part 2 the sequel // Monitor part 2 the sequel
DYNLISTENFUNC(monitorFrame); DYNLISTENFUNC(monitorFrame);
DYNLISTENFUNC(monitorDestroy); DYNLISTENFUNC(monitorDestroy);
@@ -52,16 +33,4 @@ namespace Events {
DYNLISTENFUNC(monitorNeedsFrame); DYNLISTENFUNC(monitorNeedsFrame);
DYNLISTENFUNC(monitorCommit); DYNLISTENFUNC(monitorCommit);
DYNLISTENFUNC(monitorBind); DYNLISTENFUNC(monitorBind);
// XWayland
LISTENER(surfaceXWayland);
// Renderer destroy
LISTENER(RendererDestroy);
// session
LISTENER(sessionActive);
// Session Lock
LISTENER(newSessionLock);
}; };

View File

@@ -1,43 +0,0 @@
#include "Events.hpp"
#include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "../managers/CursorManager.hpp"
// ------------------------------ //
// __ __ _____ _____ _____ //
// | \/ |_ _|/ ____|/ ____| //
// | \ / | | | | (___ | | //
// | |\/| | | | \___ \| | //
// | | | |_| |_ ____) | |____ //
// |_| |_|_____|_____/ \_____| //
// //
// ------------------------------ //
void Events::listener_leaseRequest(wl_listener* listener, void* data) {
const auto REQUEST = (wlr_drm_lease_request_v1*)data;
struct wlr_drm_lease_v1* lease = wlr_drm_lease_request_v1_grant(REQUEST);
if (!lease) {
Debug::log(ERR, "Failed to grant lease request!");
wlr_drm_lease_request_v1_reject(REQUEST);
}
}
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
Debug::log(LOG, "!!Renderer destroyed!!");
}
void Events::listener_sessionActive(wl_listener* listener, void* data) {
Debug::log(LOG, "Session got activated!");
g_pCompositor->m_bSessionActive = true;
for (auto& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m.get());
g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true);
}
g_pConfigManager->m_bWantsMonitorReload = true;
}

View File

@@ -5,6 +5,9 @@
#include "Events.hpp" #include "Events.hpp"
#include "../debug/HyprCtl.hpp" #include "../debug/HyprCtl.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../protocols/Screencopy.hpp"
#include "../protocols/ToplevelExport.hpp"
#include <aquamarine/output/Output.hpp>
// --------------------------------------------------------- // // --------------------------------------------------------- //
// __ __ ____ _ _ _____ _______ ____ _____ _____ // // __ __ ____ _ _ _____ _______ ____ _____ _____ //
@@ -16,99 +19,10 @@
// // // //
// --------------------------------------------------------- // // --------------------------------------------------------- //
static void checkDefaultCursorWarp(SP<CMonitor> PNEWMONITOR, std::string monitorName) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static auto firstMonitorAdded = std::chrono::system_clock::now();
static bool cursorDefaultDone = false;
static bool firstLaunch = true;
const auto POS = PNEWMONITOR->middle();
// by default, cursor should be set to first monitor detected
// this is needed as a default if the monitor given in config above doesn't exist
if (firstLaunch) {
firstLaunch = false;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY)
return;
// after 10s, don't set cursor to default monitor
auto timePassedSec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - firstMonitorAdded);
if (timePassedSec.count() > 10) {
cursorDefaultDone = true;
return;
}
if (*PCURSORMONITOR == monitorName) {
cursorDefaultDone = true;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
}
void Events::listener_newOutput(wl_listener* listener, void* data) {
// new monitor added, let's accommodate for that.
const auto OUTPUT = (wlr_output*)data;
if (!OUTPUT->name) {
Debug::log(ERR, "New monitor has no name?? Ignoring");
return;
}
// add it to real
auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>());
if (std::string("HEADLESS-1") == OUTPUT->name)
g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get();
PNEWMONITOR->output = OUTPUT;
PNEWMONITOR->self = PNEWMONITOR;
const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false;
PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name);
PNEWMONITOR->isUnsafeFallback = FALLBACK;
EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR);
if (!FALLBACK)
PNEWMONITOR->onConnect(false);
if (!PNEWMONITOR->m_bEnabled || FALLBACK)
return;
// ready to process if we have a real monitor
if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled)
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get();
g_pCompositor->m_bReadyToProcess = true;
g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get());
checkDefaultCursorWarp(PNEWMONITOR, OUTPUT->name);
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) {
w->m_iLastSurfaceMonitorID = -1;
w->updateSurfaceScaleTransformDetails();
}
}
}
void Events::listener_monitorFrame(void* owner, void* data) { void Events::listener_monitorFrame(void* owner, void* data) {
if (g_pCompositor->m_bExitTriggered) {
// Only signal cleanup once
g_pCompositor->m_bExitTriggered = false;
g_pCompositor->cleanup();
return;
}
CMonitor* const PMONITOR = (CMonitor*)owner; CMonitor* const PMONITOR = (CMonitor*)owner;
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!"); Debug::log(WARN, "Attempted to render frame on inactive session!");
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) { if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
@@ -172,12 +86,10 @@ void Events::listener_monitorFrame(void* owner, void* data) {
} }
void Events::listener_monitorDestroy(void* owner, void* data) { void Events::listener_monitorDestroy(void* owner, void* data) {
const auto OUTPUT = (wlr_output*)data; CMonitor* pMonitor = (CMonitor*)owner;
CMonitor* pMonitor = nullptr;
for (auto& m : g_pCompositor->m_vRealMonitors) { for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->output == OUTPUT) { if (m->output == pMonitor->output) {
pMonitor = m.get(); pMonitor = m.get();
break; break;
} }
@@ -198,44 +110,18 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP<CMonitor>& el) { return el.get() == pMonitor; }); std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP<CMonitor>& el) { return el.get() == pMonitor; });
} }
void Events::listener_monitorStateRequest(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_request_state*)data;
if (!PMONITOR->createdByUser)
return;
const auto SIZE = E->state->mode ? Vector2D{E->state->mode->width, E->state->mode->height} : Vector2D{E->state->custom_mode.width, E->state->custom_mode.height};
PMONITOR->forceSize = SIZE;
SMonitorRule rule = PMONITOR->activeMonitorRule;
rule.resolution = SIZE;
g_pHyprRenderer->applyMonitorRule(PMONITOR, &rule);
}
void Events::listener_monitorDamage(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_damage*)data;
PMONITOR->addDamage(E->damage);
}
void Events::listener_monitorNeedsFrame(void* owner, void* data) { void Events::listener_monitorNeedsFrame(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner; const auto PMONITOR = (CMonitor*)owner;
g_pCompositor->scheduleFrameForMonitor(PMONITOR); g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME);
} }
void Events::listener_monitorCommit(void* owner, void* data) { void Events::listener_monitorCommit(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner; const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_commit*)data; if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
PROTO::screencopy->onOutputCommit(PMONITOR);
if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) { PROTO::toplevelExport->onOutputCommit(PMONITOR);
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
} }
} }

View File

@@ -10,8 +10,12 @@
#include "../protocols/LayerShell.hpp" #include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp" #include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp" #include "../protocols/core/Compositor.hpp"
#include "../protocols/ToplevelExport.hpp"
#include "../xwayland/XSurface.hpp" #include "../xwayland/XSurface.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
// ------------------------------------------------------------ // // ------------------------------------------------------------ //
// __ _______ _ _ _____ ______ _______ // // __ _______ _ _ _____ ______ _______ //
// \ \ / /_ _| \ | | __ \ / __ \ \ / / ____| // // \ \ / /_ _| \ | | __ \ / __ \ \ / / ____| //
@@ -41,7 +45,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength"); static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow"); static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
static auto PSWALLOWREGEX = CConfigValue<std::string>("misc:swallow_regex"); static auto PSWALLOWREGEX = CConfigValue<std::string>("misc:swallow_regex");
static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex");
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen"); static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen");
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking"); static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
@@ -130,17 +133,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
// window rules // window rules
PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false); PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false);
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen); std::optional<eFullscreenMode> requestedInternalFSMode, requestedClientFSMode;
bool requestsFakeFullscreen = false; std::optional<sFullscreenState> requestedFSState;
bool requestsMaximize = false; if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen))
bool overridingNoFullscreen = false; requestedClientFSMode = FSMODE_FULLSCREEN;
bool overridingNoMaximize = false;
for (auto& r : PWINDOW->m_vMatchedRules) { for (auto& r : PWINDOW->m_vMatchedRules) {
if (r.szRule.starts_with("monitor")) { if (r.szRule.starts_with("monitor")) {
try { try {
const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' '))); const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' ')));
if (MONITORSTR == "unset") { if (MONITORSTR == "unset") {
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_iMonitorID = PMONITOR->ID;
@@ -194,10 +196,18 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bIsFloating = false; PWINDOW->m_bIsFloating = false;
} else if (r.szRule.starts_with("pseudo")) { } else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true; PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.starts_with("nofocus")) {
PWINDOW->m_sAdditionalConfigData.noFocus = true;
} else if (r.szRule.starts_with("noinitialfocus")) { } else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.starts_with("fullscreenstate")) {
const auto ARGS = CVarList(r.szRule.substr(r.szRule.find_first_of(' ') + 1), 2, ' ');
int internalMode, clientMode;
try {
internalMode = std::stoi(ARGS[0]);
} catch (std::exception& e) { internalMode = 0; }
try {
clientMode = std::stoi(ARGS[1]);
} catch (std::exception& e) { clientMode = 0; }
requestedFSState = sFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode};
} else if (r.szRule.starts_with("suppressevent")) { } else if (r.szRule.starts_with("suppressevent")) {
CVarList vars(r.szRule, 0, 's', true); CVarList vars(r.szRule, 0, 's', true);
for (size_t i = 1; i < vars.size(); ++i) { for (size_t i = 1; i < vars.size(); ++i) {
@@ -212,22 +222,12 @@ void Events::listener_mapWindow(void* owner, void* data) {
else else
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]); Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
} }
} else if (r.szRule == "fullscreen") {
requestsFullscreen = true;
overridingNoFullscreen = true;
} else if (r.szRule == "fakefullscreen") {
requestsFakeFullscreen = true;
} else if (r.szRule == "windowdance") {
PWINDOW->m_sAdditionalConfigData.windowDanceCompat = true;
} else if (r.szRule == "nomaxsize") {
PWINDOW->m_sAdditionalConfigData.noMaxSize = true;
} else if (r.szRule == "forceinput") {
PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true;
} else if (r.szRule == "pin") { } else if (r.szRule == "pin") {
PWINDOW->m_bPinned = true; PWINDOW->m_bPinned = true;
} else if (r.szRule == "fullscreen") {
requestedInternalFSMode = FSMODE_FULLSCREEN;
} else if (r.szRule == "maximize") { } else if (r.szRule == "maximize") {
requestsMaximize = true; requestedInternalFSMode = FSMODE_MAXIMIZED;
overridingNoMaximize = true;
} else if (r.szRule == "stayfocused") { } else if (r.szRule == "stayfocused") {
PWINDOW->m_bStayFocused = true; PWINDOW->m_bStayFocused = true;
} else if (r.szRule.starts_with("group")) { } else if (r.szRule.starts_with("group")) {
@@ -235,7 +235,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
continue; continue;
// `group` is a shorthand of `group set` // `group` is a shorthand of `group set`
if (removeBeginEndSpacesTabs(r.szRule) == "group") { if (trim(r.szRule) == "group") {
PWINDOW->m_eGroupRules |= GROUP_SET; PWINDOW->m_eGroupRules |= GROUP_SET;
continue; continue;
} }
@@ -291,8 +291,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].starts_with("silent")) if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].starts_with("silent"))
workspaceSilent = true; workspaceSilent = true;
std::string requestedWorkspaceName; const auto& [REQUESTEDWORKSPACEID, requestedWorkspaceName] = getWorkspaceIDNameFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0));
const int REQUESTEDWORKSPACEID = getWorkspaceIDFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0), requestedWorkspaceName);
if (REQUESTEDWORKSPACEID != WORKSPACE_INVALID) { if (REQUESTEDWORKSPACEID != WORKSPACE_INVALID) {
auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID); auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID);
@@ -320,7 +319,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
workspaceSilent = false; workspaceSilent = false;
} }
PWINDOW->updateSpecialRenderData(); PWINDOW->updateWindowData();
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
@@ -456,10 +455,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock(); const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock();
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) { if (PWINDOW->m_sWindowData.allowsInput.valueOrDefault()) { // if default value wasn't set to false getPriority() would throw an exception
PWINDOW->m_sAdditionalConfigData.noFocus = false; PWINDOW->m_sWindowData.noFocus = CWindowOverridableVar(false, PWINDOW->m_sWindowData.allowsInput.getPriority());
PWINDOW->m_bNoInitialFocus = false; PWINDOW->m_bNoInitialFocus = false;
PWINDOW->m_bX11ShouldntFocus = false; PWINDOW->m_bX11ShouldntFocus = false;
} }
// check LS focus grab // check LS focus grab
@@ -467,46 +466,48 @@ void Events::listener_mapWindow(void* owner, void* data) {
const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock()); const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock());
if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE)
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) {
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestedInternalFSMode.has_value() && !requestedClientFSMode.has_value() && !PWINDOW->m_bIsFloating) {
if (*PNEWTAKESOVERFS == 0) if (*PNEWTAKESOVERFS == 0)
PWINDOW->m_bNoInitialFocus = true; PWINDOW->m_bNoInitialFocus = true;
else if (*PNEWTAKESOVERFS == 1)
requestedInternalFSMode = PWINDOW->m_pWorkspace->m_efFullscreenMode;
else if (*PNEWTAKESOVERFS == 2) else if (*PNEWTAKESOVERFS == 2)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), false, FULLSCREEN_INVALID); g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE);
else if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED)
requestsMaximize = true;
else
requestsFullscreen = true;
} }
if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus && if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus &&
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && (PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) &&
!g_pInputManager->isConstrained()) { !g_pInputManager->isConstrained()) {
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH); PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH);
} else { } else {
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(0); PWINDOW->m_fDimPercent.setValueAndWarp(0);
} }
if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) || if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
(requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) { requestedClientFSMode = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)FSMODE_FULLSCREEN);
// fix fullscreen on requested (basically do a switcheroo) if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE))
if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) { requestedClientFSMode = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)FSMODE_MAXIMIZED);
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID);
g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL);
}
if (requestsFakeFullscreen && !PWINDOW->m_bFakeFullscreenState) { if (!PWINDOW->m_bNoInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) {
PWINDOW->m_bFakeFullscreenState = !PWINDOW->m_bFakeFullscreenState; // fix fullscreen on requested (basically do a switcheroo)
g_pXWaylandManager->setWindowFullscreen(PWINDOW, true); if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow)
} else { g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE);
overridingNoFullscreen = false;
overridingNoMaximize = false; PWINDOW->m_vRealPosition.warp();
PWINDOW->m_vRealPosition.warp(); PWINDOW->m_vRealSize.warp();
PWINDOW->m_vRealSize.warp(); if (requestedFSState.has_value()) {
g_pCompositor->setWindowFullscreen(PWINDOW, true, requestsFullscreen ? FULLSCREEN_FULL : FULLSCREEN_MAXIMIZED); PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE);
} g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value());
} else if (requestedInternalFSMode.has_value() && requestedClientFSMode.has_value() && !PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault())
g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = requestedInternalFSMode.value(), .client = requestedClientFSMode.value()});
else if (requestedInternalFSMode.has_value())
g_pCompositor->setWindowFullscreenInternal(PWINDOW, requestedInternalFSMode.value());
else if (requestedClientFSMode.has_value())
g_pCompositor->setWindowFullscreenClient(PWINDOW, requestedClientFSMode.value());
} }
// recheck idle inhibitors // recheck idle inhibitors
@@ -524,71 +525,17 @@ void Events::listener_mapWindow(void* owner, void* data) {
// verify swallowing // verify swallowing
if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) { if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) {
// don't swallow ourselves const auto SWALLOWER = PWINDOW->getSwallower();
std::regex rgx(*PSWALLOWREGEX);
if (!std::regex_match(PWINDOW->m_szClass, rgx)) {
// check parent
int ppid = getPPIDof(PWINDOW->getPID());
int curppid = 0; if (SWALLOWER) {
// swallow
PWINDOW->m_pSwallowed = SWALLOWER;
for (int i = 0; i < 5; ++i) { g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER);
curppid = getPPIDof(ppid);
if (curppid < 10) { SWALLOWER->setHidden(true);
break;
}
ppid = curppid; g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
}
if (ppid) {
// get window by pid
std::vector<PHLWINDOW> found;
PHLWINDOW finalFound;
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->isHidden())
continue;
if (w->getPID() == ppid) {
found.push_back(w);
}
}
if (found.size() > 1) {
for (auto& w : found) {
// try get the focus, otherwise we'll ignore to avoid swallowing incorrect windows
if (w == PFOCUSEDWINDOWPREV) {
finalFound = w;
break;
}
}
} else if (found.size() == 1) {
finalFound = found[0];
}
if (finalFound) {
bool valid = std::regex_match(PWINDOW->m_szClass, rgx);
if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) {
std::regex exc(*PSWALLOWEXREGEX);
valid = valid && !std::regex_match(PWINDOW->m_szTitle, exc);
}
// check if it's the window we want & not exempt from getting swallowed
if (valid) {
// swallow
PWINDOW->m_pSwallowed = finalFound;
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(finalFound);
finalFound->setHidden(true);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
}
}
}
} }
} }
@@ -616,7 +563,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// recalc the values for this window // recalc the values for this window
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
// avoid this window being visible // avoid this window being visible
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating) if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen() && !PWINDOW->m_bIsFloating)
PWINDOW->m_fAlpha.setValueAndWarp(0.f); PWINDOW->m_fAlpha.setValueAndWarp(0.f);
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale); g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale);
@@ -639,6 +586,11 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "{:c} unmapped", PWINDOW); Debug::log(LOG, "{:c} unmapped", PWINDOW);
static auto PEXITRETAINSFS = CConfigValue<Hyprlang::INT>("misc:exit_window_retains_fullscreen");
const auto CURRENTWINDOWFSSTATE = PWINDOW->isFullscreen();
const auto CURRENTFSMODE = PWINDOW->m_sFullscreenState.internal;
if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) { if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) {
Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW); Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW);
PWINDOW->m_bFadingOut = false; PWINDOW->m_bFadingOut = false;
@@ -655,10 +607,10 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)}); g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)});
EMIT_HOOK_EVENT("closeWindow", PWINDOW); EMIT_HOOK_EVENT("closeWindow", PWINDOW);
g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW); PROTO::toplevelExport->onWindowUnmap(PWINDOW);
if (PWINDOW->m_bIsFullscreen) if (PWINDOW->isFullscreen())
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE);
// Allow the renderer to catch the last frame. // Allow the renderer to catch the last frame.
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW); g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
@@ -680,10 +632,13 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pInputManager->releaseAllMouseButtons(); g_pInputManager->releaseAllMouseButtons();
} }
if (PWINDOW == g_pInputManager->currentlyDraggedWindow.lock())
g_pKeybindManager->changeMouseBindMode(MBIND_INVALID);
// remove the fullscreen window status from workspace if we closed it // remove the fullscreen window status from workspace if we closed it
const auto PWORKSPACE = PWINDOW->m_pWorkspace; const auto PWORKSPACE = PWINDOW->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && PWINDOW->m_bIsFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && PWINDOW->isFullscreen())
PWORKSPACE->m_bHasFullscreenWindow = false; PWORKSPACE->m_bHasFullscreenWindow = false;
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
@@ -697,8 +652,11 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE); Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE);
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) {
g_pCompositor->focusWindow(PWINDOWCANDIDATE); g_pCompositor->focusWindow(PWINDOWCANDIDATE);
if (*PEXITRETAINSFS && CURRENTWINDOWFSSTATE)
g_pCompositor->setWindowFullscreenInternal(PWINDOWCANDIDATE, CURRENTFSMODE);
}
if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0) if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0)
g_pInputManager->refocus(); g_pInputManager->refocus();
@@ -753,14 +711,9 @@ void Events::listener_commitWindow(void* owner, void* data) {
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden()) if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
return; return;
if (PWINDOW->m_bIsX11) PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
else if (PWINDOW->m_pPendingSizeAck.has_value()) {
PWINDOW->m_vReportedSize = PWINDOW->m_pPendingSizeAck->second;
PWINDOW->m_pPendingSizeAck.reset();
}
if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) { if (!PWINDOW->m_bIsX11 && !PWINDOW->isFullscreen() && PWINDOW->m_bIsFloating) {
const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize;
const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize; const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize;
@@ -799,8 +752,8 @@ void Events::listener_commitWindow(void* owner, void* data) {
// tearing: if solitary, redraw it. This still might be a single surface window // tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) { if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.bufferDamage}; CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
if (!damageBox.empty()) { if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) { if (PMONITOR->tearingState.busy) {
@@ -837,6 +790,11 @@ void Events::listener_destroyWindow(void* owner, void* data) {
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW); Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
} }
PWINDOW->listeners.unmap.reset();
PWINDOW->listeners.destroy.reset();
PWINDOW->listeners.map.reset();
PWINDOW->listeners.commit.reset();
} }
void Events::listener_setTitleWindow(void* owner, void* data) { void Events::listener_setTitleWindow(void* owner, void* data) {
@@ -887,7 +845,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
else else
PWINDOW->setHidden(true); PWINDOW->setHidden(true);
if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) { if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
return; return;

View File

@@ -57,11 +57,11 @@ void CBaseAnimatedVariable::registerVar() {
int CBaseAnimatedVariable::getDurationLeftMs() { int CBaseAnimatedVariable::getDurationLeftMs() {
return std::max( return std::max(
(int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0); (int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - animationBegin).count(), 0);
} }
float CBaseAnimatedVariable::getPercent() { float CBaseAnimatedVariable::getPercent() {
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(); const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - animationBegin).count();
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f); return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
} }

View File

@@ -4,7 +4,7 @@
#include <any> #include <any>
#include <chrono> #include <chrono>
#include <type_traits> #include <type_traits>
#include "Vector2D.hpp" #include "math/Math.hpp"
#include "Color.hpp" #include "Color.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../debug/Log.hpp" #include "../debug/Log.hpp"
@@ -155,7 +155,7 @@ class CBaseAnimatedVariable {
bool m_bIsRegistered = false; bool m_bIsRegistered = false;
bool m_bIsBeingAnimated = false; bool m_bIsBeingAnimated = false;
std::chrono::system_clock::time_point animationBegin; std::chrono::steady_clock::time_point animationBegin;
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE; AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE;
ANIMATEDVARTYPE m_Type; ANIMATEDVARTYPE m_Type;
@@ -253,7 +253,7 @@ class CAnimatedVariable : public CBaseAnimatedVariable {
return *this; return *this;
m_Goal = v; m_Goal = v;
animationBegin = std::chrono::system_clock::now(); animationBegin = std::chrono::steady_clock::now();
m_Begun = m_Value; m_Begun = m_Value;
onAnimationBegin(); onAnimationBegin();
@@ -267,7 +267,7 @@ class CAnimatedVariable : public CBaseAnimatedVariable {
return; return;
m_Value = v; m_Value = v;
animationBegin = std::chrono::system_clock::now(); animationBegin = std::chrono::steady_clock::now();
m_Begun = m_Value; m_Begun = m_Value;
onAnimationBegin(); onAnimationBegin();

View File

@@ -30,8 +30,10 @@ void CBezierCurve::setup(std::vector<Vector2D>* pVec) {
const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f; const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f;
const auto BEGINCALC = std::chrono::high_resolution_clock::now(); const auto BEGINCALC = std::chrono::high_resolution_clock::now();
for (float i = 0.1f; i < 1.f; i += 0.1f) for (int j = 1; j < 10; ++j) {
float i = j / 10.0f;
getYForPoint(i); getYForPoint(i);
}
const auto ELAPSEDCALCAVG = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f; const auto ELAPSEDCALCAVG = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f;
Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE, Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE,

View File

@@ -3,7 +3,7 @@
#include <deque> #include <deque>
#include <array> #include <array>
#include <vector> #include <vector>
#include "Vector2D.hpp" #include "math/Math.hpp"
constexpr int BAKEDPOINTS = 255; constexpr int BAKEDPOINTS = 255;
constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS; constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS;

View File

@@ -1,179 +0,0 @@
#include "Box.hpp"
#include <limits>
#include <algorithm>
wlr_box CBox::wlr() {
CBox rounded = roundInternal();
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
return m_bWlrBox;
}
wlr_box* CBox::pWlr() {
CBox rounded = roundInternal();
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
return &m_bWlrBox;
}
CBox& CBox::scale(double scale) {
x *= scale;
y *= scale;
w *= scale;
h *= scale;
return *this;
}
CBox& CBox::scale(const Vector2D& scale) {
x *= scale.x;
y *= scale.y;
w *= scale.x;
h *= scale.y;
return *this;
}
CBox& CBox::translate(const Vector2D& vec) {
x += vec.x;
y += vec.y;
return *this;
}
Vector2D CBox::middle() const {
return Vector2D{x + w / 2.0, y + h / 2.0};
}
bool CBox::containsPoint(const Vector2D& vec) const {
return VECINRECT(vec, x, y, x + w, y + h);
}
bool CBox::empty() const {
return w == 0 || h == 0;
}
CBox& CBox::applyFromWlr() {
x = m_bWlrBox.x;
y = m_bWlrBox.y;
w = m_bWlrBox.width;
h = m_bWlrBox.height;
return *this;
}
CBox& CBox::round() {
float newW = x + w - std::round(x);
float newH = y + h - std::round(y);
x = std::round(x);
y = std::round(y);
w = std::round(newW);
h = std::round(newH);
return *this;
}
CBox& CBox::transform(const wl_output_transform t, double w, double h) {
wlr_box_transform(&m_bWlrBox, pWlr(), t, w, h);
applyFromWlr();
return *this;
}
CBox& CBox::addExtents(const SWindowDecorationExtents& e) {
x -= e.topLeft.x;
y -= e.topLeft.y;
w += e.topLeft.x + e.bottomRight.x;
h += e.topLeft.y + e.bottomRight.y;
return *this;
}
CBox& CBox::scaleFromCenter(double scale) {
double oldW = w, oldH = h;
w *= scale;
h *= scale;
x -= (w - oldW) / 2.0;
y -= (h - oldH) / 2.0;
return *this;
}
CBox& CBox::expand(const double& value) {
x -= value;
y -= value;
w += value * 2.0;
h += value * 2.0;
if (w <= 0 || h <= 0) {
w = 0;
h = 0;
}
return *this;
}
CBox& CBox::noNegativeSize() {
w = std::clamp(w, 0.0, std::numeric_limits<double>::infinity());
h = std::clamp(h, 0.0, std::numeric_limits<double>::infinity());
return *this;
}
CBox CBox::intersection(const CBox& other) const {
const float newX = std::max(x, other.x);
const float newY = std::max(y, other.y);
const float newBottom = std::min(y + h, other.y + other.h);
const float newRight = std::min(x + w, other.x + other.w);
float newW = newRight - newX;
float newH = newBottom - newY;
if (newW <= 0 || newH <= 0) {
newW = 0;
newH = 0;
}
return {newX, newY, newW, newH};
}
bool CBox::overlaps(const CBox& other) const {
return (other.x + other.w >= x) && (x + w >= other.x) && (other.y + other.h >= y) && (y + h >= other.y);
}
bool CBox::inside(const CBox& bound) const {
return bound.x < x && bound.y < y && x + w < bound.x + bound.w && y + h < bound.y + bound.h;
}
CBox CBox::roundInternal() {
float newW = x + w - std::floor(x);
float newH = y + h - std::floor(y);
return CBox{std::floor(x), std::floor(y), std::floor(newW), std::floor(newH)};
}
CBox CBox::copy() const {
return CBox{*this};
}
Vector2D CBox::pos() const {
return {x, y};
}
Vector2D CBox::size() const {
return {w, h};
}
Vector2D CBox::closestPoint(const Vector2D& vec) const {
if (containsPoint(vec))
return vec;
Vector2D nv = vec;
nv.x = std::clamp(nv.x, x, x + w);
nv.y = std::clamp(nv.y, y, y + h);
return nv;
}
SWindowDecorationExtents CBox::extentsFrom(const CBox& small) {
return {{small.x - x, small.y - y}, {w - small.w - (small.x - x), h - small.h - (small.y - y)}};
}

View File

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

View File

@@ -0,0 +1,43 @@
#pragma once
#include <array>
// clang-format off
constexpr std::array<const char*, 35> CURSOR_SHAPE_NAMES = {
"invalid",
"default",
"context-menu",
"help",
"pointer",
"progress",
"wait",
"cell",
"crosshair",
"text",
"vertical-text",
"alias",
"copy",
"move",
"no-drop",
"not-allowed",
"grab",
"grabbing",
"e-resize",
"n-resize",
"ne-resize",
"nw-resize",
"s-resize",
"se-resize",
"sw-resize",
"w-resize",
"ew-resize",
"ns-resize",
"nesw-resize",
"nwse-resize",
"col-resize",
"row-resize",
"all-scroll",
"zoom-in",
"zoom-out",
};
// clang-format on

View File

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

View File

@@ -0,0 +1,22 @@
#pragma once
#include "./math/Math.hpp"
#include <array>
constexpr static int DAMAGE_RING_PREVIOUS_LEN = 2;
class CDamageRing {
public:
void setSize(const Vector2D& size_);
bool damage(const CRegion& rg);
void damageEntire();
void rotate();
CRegion getBufferDamage(int age);
bool hasChanged();
private:
Vector2D size;
CRegion current;
std::array<CRegion, DAMAGE_RING_PREVIOUS_LEN> previous;
size_t previousIdx = 0;
};

View File

@@ -2,6 +2,9 @@
#include <vector> #include <vector>
#include "../includes.hpp" #include "../includes.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
#include "../macros.hpp"
#include <xf86drm.h>
#include <drm_fourcc.h>
/* /*
DRM formats are LE, while OGL is BE. The two primary formats DRM formats are LE, while OGL is BE. The two primary formats
@@ -11,18 +14,26 @@
*/ */
inline const std::vector<SPixelFormat> GLES3_FORMATS = { inline const std::vector<SPixelFormat> GLES3_FORMATS = {
{ {
.drmFormat = DRM_FORMAT_ARGB8888, .drmFormat = DRM_FORMAT_ARGB8888,
.flipRB = true, .flipRB = true,
.glFormat = GL_RGBA, #ifndef GLES2
.glFormat = GL_RGBA,
#else
.glFormat = GL_BGRA_EXT,
#endif
.glType = GL_UNSIGNED_BYTE, .glType = GL_UNSIGNED_BYTE,
.withAlpha = true, .withAlpha = true,
.alphaStripped = DRM_FORMAT_XRGB8888, .alphaStripped = DRM_FORMAT_XRGB8888,
.bytesPerBlock = 4, .bytesPerBlock = 4,
}, },
{ {
.drmFormat = DRM_FORMAT_XRGB8888, .drmFormat = DRM_FORMAT_XRGB8888,
.flipRB = true, .flipRB = true,
.glFormat = GL_RGBA, #ifndef GLES2
.glFormat = GL_RGBA,
#else
.glFormat = GL_BGRA_EXT,
#endif
.glType = GL_UNSIGNED_BYTE, .glType = GL_UNSIGNED_BYTE,
.withAlpha = false, .withAlpha = false,
.alphaStripped = DRM_FORMAT_XRGB8888, .alphaStripped = DRM_FORMAT_XRGB8888,
@@ -93,70 +104,100 @@ inline const std::vector<SPixelFormat> GLES3_FORMATS = {
.bytesPerBlock = 2, .bytesPerBlock = 2,
}, },
{ {
.drmFormat = DRM_FORMAT_XBGR2101010, .drmFormat = DRM_FORMAT_XBGR2101010,
.glFormat = GL_RGBA, .glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV, #ifndef GLES2
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
#else
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
#endif
.withAlpha = false, .withAlpha = false,
.alphaStripped = DRM_FORMAT_XBGR2101010, .alphaStripped = DRM_FORMAT_XBGR2101010,
.bytesPerBlock = 4, .bytesPerBlock = 4,
}, },
{ {
.drmFormat = DRM_FORMAT_ABGR2101010, .drmFormat = DRM_FORMAT_ABGR2101010,
.glFormat = GL_RGBA, .glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV, #ifndef GLES2
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
#else
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
#endif
.withAlpha = true, .withAlpha = true,
.alphaStripped = DRM_FORMAT_XBGR2101010, .alphaStripped = DRM_FORMAT_XBGR2101010,
.bytesPerBlock = 4, .bytesPerBlock = 4,
}, },
{ {
.drmFormat = DRM_FORMAT_XRGB2101010, .drmFormat = DRM_FORMAT_XRGB2101010,
.glFormat = GL_RGBA, .glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV, #ifndef GLES2
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
#else
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
#endif
.withAlpha = false, .withAlpha = false,
.alphaStripped = DRM_FORMAT_XRGB2101010, .alphaStripped = DRM_FORMAT_XRGB2101010,
.bytesPerBlock = 4, .bytesPerBlock = 4,
}, },
{ {
.drmFormat = DRM_FORMAT_ARGB2101010, .drmFormat = DRM_FORMAT_ARGB2101010,
.glFormat = GL_RGBA, .glFormat = GL_RGBA,
.glType = GL_UNSIGNED_INT_2_10_10_10_REV, #ifndef GLES2
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
#else
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
#endif
.withAlpha = true, .withAlpha = true,
.alphaStripped = DRM_FORMAT_XRGB2101010, .alphaStripped = DRM_FORMAT_XRGB2101010,
.bytesPerBlock = 4, .bytesPerBlock = 4,
}, },
{ {
.drmFormat = DRM_FORMAT_XBGR16161616F, .drmFormat = DRM_FORMAT_XBGR16161616F,
.glFormat = GL_RGBA, .glFormat = GL_RGBA,
.glType = GL_HALF_FLOAT, #ifndef GLES2
.glType = GL_HALF_FLOAT,
#else
.glType = GL_HALF_FLOAT_OES,
#endif
.withAlpha = false, .withAlpha = false,
.alphaStripped = DRM_FORMAT_XBGR16161616F, .alphaStripped = DRM_FORMAT_XBGR16161616F,
.bytesPerBlock = 8, .bytesPerBlock = 8,
}, },
{ {
.drmFormat = DRM_FORMAT_ABGR16161616F, .drmFormat = DRM_FORMAT_ABGR16161616F,
.glFormat = GL_RGBA, .glFormat = GL_RGBA,
.glType = GL_HALF_FLOAT, #ifndef GLES2
.glType = GL_HALF_FLOAT,
#else
.glType = GL_HALF_FLOAT_OES,
#endif
.withAlpha = true, .withAlpha = true,
.alphaStripped = DRM_FORMAT_XBGR16161616F, .alphaStripped = DRM_FORMAT_XBGR16161616F,
.bytesPerBlock = 8, .bytesPerBlock = 8,
}, },
{ {
.drmFormat = DRM_FORMAT_XBGR16161616, .drmFormat = DRM_FORMAT_XBGR16161616,
.glInternalFormat = GL_RGBA16UI, #ifndef GLES2
.glFormat = GL_RGBA, .glFormat = GL_RGBA16UI,
.glType = GL_UNSIGNED_SHORT, #else
.withAlpha = false, .glFormat = GL_RGBA16_EXT,
.alphaStripped = DRM_FORMAT_XBGR16161616, #endif
.bytesPerBlock = 8, .glType = GL_UNSIGNED_SHORT,
.withAlpha = false,
.alphaStripped = DRM_FORMAT_XBGR16161616,
.bytesPerBlock = 8,
}, },
{ {
.drmFormat = DRM_FORMAT_ABGR16161616, .drmFormat = DRM_FORMAT_ABGR16161616,
.glInternalFormat = GL_RGBA16UI, #ifndef GLES2
.glFormat = GL_RGBA, .glFormat = GL_RGBA16UI,
.glType = GL_UNSIGNED_SHORT, #else
.withAlpha = true, .glFormat = GL_RGBA16_EXT,
.alphaStripped = DRM_FORMAT_XBGR16161616, #endif
.bytesPerBlock = 8, .glType = GL_UNSIGNED_SHORT,
.withAlpha = true,
.alphaStripped = DRM_FORMAT_XBGR16161616,
.bytesPerBlock = 8,
}, },
{ {
.drmFormat = DRM_FORMAT_YVYU, .drmFormat = DRM_FORMAT_YVYU,
@@ -270,3 +311,17 @@ uint32_t FormatUtils::glFormatToType(uint32_t gl) {
#endif #endif
GL_UNSIGNED_BYTE; GL_UNSIGNED_BYTE;
} }
std::string FormatUtils::drmFormatName(DRMFormat drm) {
auto n = drmGetFormatName(drm);
std::string name = n;
free(n);
return name;
}
std::string FormatUtils::drmModifierName(uint64_t mod) {
auto n = drmGetFormatModifierName(mod);
std::string name = n;
free(n);
return name;
}

View File

@@ -1,7 +1,9 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include "Vector2D.hpp" #include <string>
#include "math/Math.hpp"
#include <aquamarine/backend/Misc.hpp>
typedef uint32_t DRMFormat; typedef uint32_t DRMFormat;
typedef uint32_t SHMFormat; typedef uint32_t SHMFormat;
@@ -18,10 +20,7 @@ struct SPixelFormat {
Vector2D blockSize; Vector2D blockSize;
}; };
struct SDRMFormat { typedef Aquamarine::SDRMFormat SDRMFormat;
uint32_t format = 0;
std::vector<uint64_t> mods;
};
namespace FormatUtils { namespace FormatUtils {
SHMFormat drmToShm(DRMFormat drm); SHMFormat drmToShm(DRMFormat drm);
@@ -34,4 +33,6 @@ namespace FormatUtils {
int minStride(const SPixelFormat* const fmt, int32_t width); int minStride(const SPixelFormat* const fmt, int32_t width);
uint32_t drmFormatToGL(DRMFormat drm); uint32_t drmFormatToGL(DRMFormat drm);
uint32_t glFormatToType(uint32_t gl); uint32_t glFormatToType(uint32_t gl);
std::string drmFormatName(DRMFormat drm);
std::string drmModifierName(uint64_t mod);
}; };

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