Compare commits

...

515 Commits

Author SHA1 Message Date
Vaxry
4520b30d49 version: bump to 0.44.1 2024-10-09 13:54:39 +01:00
trianta
8405aa111d output: update state even if no owner exists (#8044) 2024-10-09 13:47:52 +01:00
Vaxry
ad46257cce output/xdg-output: avoid sending events to released globals
ref #6835
2024-10-09 13:47:52 +01:00
Vaxry
0cfbe618b5 keyboard: update group state on change for the sym resolve state
fixes #8038
2024-10-09 13:47:52 +01:00
Vaxry
7d0944acdf defaultConfig: add a nofocus rule for weird X windows
ref #6543
2024-10-09 13:47:52 +01:00
Vaxry
b9990468f3 pointer: expand sw cursor damage box
fixes #8031

just a bit, rounding errors I guess
2024-10-09 13:47:52 +01:00
vaxerski
736a8735b3 keybinds: fixup xkb_states for resolve_by_sym
fixes #7750
2024-10-09 13:47:52 +01:00
Vaxry
b54eecbd79 config: give simple help for super+q not working
only on default config :P
2024-10-09 13:47:52 +01:00
Ikalco
657aeb3946 screencopy: fix screencopy frames not being cleaned up (#8017)
---------

Co-authored-by: Vaxry <vaxry@vaxry.net>
2024-10-09 13:47:52 +01:00
Aqa-Ib
6807430b18 layout: fix auto group when opening a new window in a non-focused workspace using window rules (#8006) 2024-10-09 13:47:52 +01:00
Vaxry
0c7a7e2d56 version: bump to 0.44.0 2024-10-06 12:04:13 +01:00
Vaxry
0ec6072a29 single-pixel: set buffer size to 1,1 2024-10-05 16:36:57 +01:00
Vaxry
3ca699debf opengl: use GL_CLAMP_TO_EDGE instead of GL_CLAMP
avoid error spam on select hw
2024-10-05 14:57:18 +01:00
Vaxry
52c0919621 monitor: arrange monitors on connect and disconnect 2024-10-05 14:41:44 +01:00
Vaxry
6fbfeefc71 protocolmgr: don't expose the fallback output 2024-10-05 14:40:03 +01:00
Vaxry
46bf87c8d1 monitor: use a scope guard for disconnect events 2024-10-05 14:37:12 +01:00
Vaxry
595eb89f6e renderer: Fix resize artifacts (stretching, bumps) (#7499) 2024-10-05 01:01:21 +01:00
Vaxry
a815b14bf1 monitor: cleanup and modernize scheduleDone 2024-10-05 01:01:21 +01:00
Vaxry
3a5052a714 compositor: update all xdg outputs on arrange 2024-10-05 01:01:21 +01:00
Vaxry
8e237b006f xdg-output: minor cleanups 2024-10-05 01:01:20 +01:00
Theo Paris
1ed925b69c internal: fix missing include directive (#7984)
This should fix building with clang.
2024-10-04 09:41:27 +01:00
Maximilian Seidler
aed529f695 renderer: fix uvBR calculation (#7975) 2024-10-03 23:00:44 +01:00
Aqa-Ib
de68e065fe layout: fix dragging a window into a group after e242694 (#7976) 2024-10-02 21:25:25 +01:00
Aqa-Ib
e2426942e5 layout: add auto_group to control default grouping (#7883) 2024-10-02 10:22:19 +01:00
Vaxry
5c6c300abf wayland/output: send geometry in updateState 2024-09-30 17:42:36 +01:00
Vaxry
6bd3397141 wlr-output-management: accept 0 refresh rates
fixes #7879
2024-09-30 17:40:38 +01:00
Vaxry
68fd32c810 byteoperations: add missing header 2024-09-30 17:27:10 +01:00
Vaxry
3ddb16bd5b compositor/wayland: up the max buffer size to avoid disconnects when app hangs 2024-09-30 17:25:57 +01:00
Trianta
f6387536f6 protocol: fix missing include 2024-09-30 10:06:39 +03:00
Trianta
968f6a6013 meson: fix arch build with new protocol 2024-09-30 10:06:39 +03:00
Vaxry
488efab636 single-pixel-buffer: new protocol impl
fixes #6624
2024-09-30 00:58:16 +01:00
Gliczy
6649255d54 flake.lock: update 2024-09-29 17:56:27 +03:00
Luke Chen
4b00cba319 dwindle: add movetoroot method to layout messages (#7903) 2024-09-29 14:47:59 +01:00
Mike Will
9e418671e1 config: add descriptions for dwindle and master layout options (#7933) 2024-09-29 14:42:10 +01:00
Mihai Fufezan
d73c14751a CI/Nix: git+https -> github 2024-09-28 21:53:18 +03:00
bivsk
6f313de952 core: Fix Musl builds (#7934)
Musl does not include the internal type `__time_t`.
Use `time_t` instead.
2024-09-28 13:46:31 +01:00
Mike Will
2cf6e7862a dwindle: add config option split_bias (#7920)
If `default_split_ratio` is greater than 1.0, `split_bias` will give the
bigger half to a specific window:

0 - positional (default)
1 - current window
2 - opening window
2024-09-28 01:49:40 +01:00
Mihai Fufezan
58669fef77 flake.lock: update 2024-09-27 18:35:29 +03:00
Vaxry
e20aef7d53 opengl: remove debug log 2024-09-26 22:34:33 +01:00
Mihai Fufezan
b2143a98e2 CI/Nix: no longer build with submodules 2024-09-27 00:07:52 +03:00
Mihai Fufezan
f75f8efb1b Meson: add tracy dependency 2024-09-27 00:07:52 +03:00
Mihai Fufezan
be96787ed0 CMake: use udis86 from pkg-config, fallback to subproject
Only canihavesomecoffee's fork (the one the subproject uses) provides
a .pc file, so we either find the correct version or we use the
subproject.
2024-09-27 00:07:52 +03:00
Mihai Fufezan
89d945aabe CMake: use hyprland-protocols from pkg-config, fallback to subproject
protocolnew: fix external path, which may not be in $CMAKE_SOURCE_DIR
2024-09-27 00:07:52 +03:00
Mihai Fufezan
27211c71e9 Meson: try to find udis86 through pkgconfig, fallback to subproject
Only the fork provides a .pc file, so there's no risk of linking the wrong
lib version. If pkg-config can't find it (most cases), fall back to using
the subproject through the wrap file.
2024-09-27 00:07:52 +03:00
Mihai Fufezan
14942bca60 Nix: re-add hyprland-protocols 2024-09-27 00:07:52 +03:00
Mihai Fufezan
77f2a01304 flake.lock: update nixpkgs 2024-09-26 21:17:07 +03:00
Mihai Fufezan
7b56ce6521 CI/Nix: add cross build 2024-09-26 21:17:07 +03:00
Jörg Thalheim
32a8caf7e7 Nix: also test cross build 2024-09-26 21:17:07 +03:00
Vaxry
caaa9b11e4 wlr-output-configuration: Improve output configuration (#7571) 2024-09-26 11:10:53 +01:00
Kamikadze
b1ad2d8066 dispatchers: fixup dpms toggle (#7875)
now toggles every monitor individually
2024-09-26 00:08:50 +01:00
Vaxry
22746b3046 hyprctl: use the getMonitorData helper everywhere 2024-09-25 23:38:11 +01:00
Vaxry
49713fab04 pointermgr: avoid hogging CMonitor refs 2024-09-25 23:15:41 +01:00
vaxerski
8b86ee8bf0 github: encourage usage of --systeminfo if Hyprland won't launch 2024-09-25 10:39:33 +01:00
vaxerski
2a052c69f3 core: add a --systeminfo parameter to gather systeminfo without running 2024-09-25 10:36:51 +01:00
Vaxry
2320b2241c Internal: move to Mat3x3 from hyprutils (#7902)
* Meson: require hyprutils >= 0.2.3

* flake.lock: update hyprutils

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-09-25 10:01:13 +01:00
vaxerski
8f5188269b hyprctl: add solitary field to hyprctl monitors 2024-09-25 09:59:18 +01:00
vaxerski
00c8626863 hyprctl: add submap request
fixes #7898
2024-09-24 11:25:05 +01:00
Vaxry
0a211f29f5 hyprctl: add defaultName to workspacerules
fixes #7886
2024-09-24 01:19:05 +01:00
Vaxry
d279d7c4c6 eventloop: dispatch pending in session on start
fixes #7855 #7391
2024-09-24 00:49:29 +01:00
diniamo
6c78b03bb7 flake: update xdph 2024-09-24 00:47:34 +01:00
Vaxry
f79497087b internal: nuke wlsignal and related
old semi-wrappers for wl_signal, they are no longer used
2024-09-24 00:47:34 +01:00
Artur Manuel
508bde1f61 core: add HYPRLAND_CONFIG environment variable (#7851) 2024-09-23 16:40:19 +01:00
diniamo
e5ff19ac0f flake: update xdph 2024-09-22 11:55:13 +03:00
Mihai Fufezan
8579066c7a Nix: clean up derivation 2024-09-21 14:27:13 +03:00
Vaxry
9232bc2c00 internal: move to hyprutils' scopeguard
bumps hyprutils dep to 0.2.2
2024-09-21 00:37:17 +01:00
Vaxry
db0b764a5a shm: send a static list of shm formats
fixes #7733
2024-09-20 22:56:15 +01:00
Mihai Fufezan
278583b8a1 flake.lock: update 2024-09-20 20:16:13 +03:00
Jasson
4414cd07e2 xwm: Minor cleanup, add wrappers for basic types (#7856) 2024-09-20 12:32:04 +01:00
Vaxry
9e98fb0167 dmabuffer: attempt importing failed dmabufs as implicit
don't ask me why, vulkan doesn't like this.

funny note, broken on wlroots :P

fixes #7037
2024-09-20 10:47:41 +01:00
Mihai Fufezan
9856378384 Nix: use mold linker 2024-09-19 18:53:34 +03:00
Mihai Fufezan
dfa1bd0cd4 Meson: pass AQUAMARINE_VERSION argument 2024-09-19 13:48:31 +00:00
vaxerski
92df6b0dce version: log build aquamarine version
log the built against aq version, might be useful when it's mismatched to identify the problem
2024-09-19 11:40:00 +01:00
vaxerski
71963972bf args: add --version to binary args 2024-09-19 11:40:00 +01:00
Arisa Snowbell
1bc05b1f9f xwayland: use proper path for the XWayland sockets (#7852)
fixes #7849
2024-09-19 11:08:02 +01:00
Vaxry
e6cf643f5a pointermgr: Hide hardware cursor on leave (#7806) 2024-09-18 18:47:53 +01:00
Jasson
94140e886e xwayland: Some readability improvements (#7807)
* Readability improvements xwayland server

* Made requested changes

* removed braces

* fix

* Ok this time is fixed

* Formatting
2024-09-18 18:12:26 +01:00
Mihai Fufezan
b248d59713 Nix: fix meson PCH flag 2024-09-18 19:43:56 +03:00
Mihai Fufezan
cbc0ff6ec0 Nix: disable PCH 2024-09-18 18:54:00 +03:00
Mihai Fufezan
6b6554adb8 flake.nix: inherit stdenv from package
Means we no longer have to change the base stdenv in two places.
2024-09-18 18:43:39 +03:00
Mihai Fufezan
d936eb437b flake.lock: update aquamarine 2024-09-18 17:26:51 +03:00
vaxerski
883d01084c userchecks: add an xdg_current_desktop check
ref https://github.com/hyprwm/xdg-desktop-portal-hyprland/issues/251

if the XDG_CURRENT_DESKTOP is externally managed (e.g. DE, DM, etc) Hyprland will not overwrite it. In those cases, if that's undesired, portals and other apps depending on it might break.
2024-09-18 11:22:12 +01:00
Aqa-Ib
0564b46a5e dispatchers: allow moveintogroup when floating (#7818)
This allows to use the moveintogroup dispatcher when windows are floating. I don't know why was this disabled in the first place though.

Cheers!
2024-09-18 11:05:17 +01:00
André Silva
3c9716acfd gammactrl: fix potential crash on monitor removed (#7828) 2024-09-17 14:37:20 +01:00
vaxerski
581f6659f8 data-device: conform to reported source actions
fixes #7815
2024-09-17 12:55:48 +01:00
vaxerski
e72ae6b25f hyprctl: allow parsing empty value
fixes #7821
2024-09-17 11:24:54 +01:00
Leiser Fernández Gallo
9e35656244 internal: Delay monitor events/hooks (#7797)
* Delay monitor messages

* Format
2024-09-15 21:03:42 +01:00
AlvinaNancy
e87758529e internal: Fix change group current fullscreen state query (#7802) 2024-09-15 18:25:06 +01:00
Sungyoon Cho
eb97d949aa textinput: don't reset if ti isn't enabled (#7798) 2024-09-15 17:31:38 +01:00
Ikalco
e74efd87e5 internal: fix initial cursor warping (#7793) 2024-09-14 23:37:18 +01:00
Vaxry
4dbdb556fe data-device: don't send default action of move
gtk doesn't like it?
2024-09-14 23:36:06 +01:00
Vaxry
5ee4b19691 data-device: send clock time in motion events
remove hack
2024-09-14 23:35:45 +01:00
Vaxry
d35e70a8c6 cmake: drop ninja dep 2024-09-13 17:56:44 +01:00
diniamo
c35ed8363f nix: adapt cmake options 2024-09-13 19:44:38 +03:00
diniamo
d505b33665 nix: use meson 2024-09-13 17:54:49 +03:00
Sungyoon Cho
118be4dea0 textinput: fix tiv3 leave (#7761) 2024-09-12 17:41:24 +01:00
trianta
73b9756b8d xwayland: remove extra x11 deactivation (#7755) 2024-09-12 10:15:01 +01:00
fufexan
8b9e385943 [gha] Nix: update inputs 2024-09-11 16:10:51 +00:00
Mihai Fufezan
e01da1fd7a Meson: format 2024-09-11 19:09:17 +03:00
Mihai Fufezan
7a8c013edc Meson: fix protocols, clean up 2024-09-11 19:09:16 +03:00
Vaxry
518399a95b pointermgr: avoid derefing null outputs 2024-09-11 09:30:21 +01:00
Sungyoon Cho
155d44016d textinput: handle IME resetting (#7731) 2024-09-10 14:49:10 +01:00
Alexandre Acebedo
13f90bb87a update xdph commit in flake.lock 2024-09-10 16:38:47 +03:00
davc0n
c67b257e51 build: Set cmake_minimum_required to version 3.30 (#7709)
* build: Set cmake_minimum_required to version 3.30

* Nix: add patch for CMake min ver

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-09-10 11:06:37 +01:00
Maximilian Seidler
8237d7e1a4 input: move dmps activation to input listeners (#7721) 2024-09-09 21:29:00 +01:00
vaxerski
85da1a17d8 [gha] build man pages 2024-09-09 15:19:44 +00:00
justmessingaround
9609b04ff9 man: Fixed the man page to show the new information (#7713)
* Update Hyprland.1.rst

* Update Hyprland.1
2024-09-09 16:19:17 +01:00
darkwater
04421063af config: add order rule for layers (#7697) 2024-09-09 10:10:08 +01:00
davc0n
43e1415e71 assets: Remove execute permission from lockdead.png (#7715) 2024-09-09 10:01:26 +01:00
Sungyoon Cho
e1448732b3 tiv1: fix deleting first character (#7716) 2024-09-09 09:58:44 +01:00
Richard Ayotte
7c4c402bd7 config: include XF86Audio* key bindings to default cfg (#7695) 2024-09-08 22:04:07 +01:00
Aqa-Ib
6179b17903 github: improve issue template (#7699)
* github: improve issue template

Require to check that you have searched through open and closed issues before committing.

* fix yaml syntax

* clarify text

* validation

* revert validation

* markdown

* done
2024-09-08 21:12:01 +01:00
Davide Conti
05b48d48d9 config: Limit max volume to 100% 2024-09-08 22:53:28 +03:00
diniamo
07a21fdfa9 github(nix-build): switch to better nix installer, attempt at fixing hash mismatch (#7701)
* github(nix-build): switch to DeterminateSystems/nix-installer-action

* github(nix-build): switch to a direct git reference instead of cloning

* github(nix-ci): attempt to fix CI for pull requests
2024-09-08 21:20:45 +03:00
Vaxry
0f594732b0 props: bump version to 0.43.0 2024-09-08 17:48:21 +01:00
Vaxry
312411fc70 windows: support size with pseudo tiled
fixes #7690
2024-09-08 00:46:46 +01:00
trianta
70add904c4 config: add exec-shutdown for running commands on shutdown (#7683)
* config: add exec-shutdown for running commands on shutdown

* compositor: delay stopping until after exec-shutdown
2024-09-07 20:54:33 +01:00
Darth ŠČ!
5ca4823128 config: Added default button mapping for xf86 keys (#7672)
* Added default button mapping for laptop multimedia keys for volume and brightness

* Added default button mapping for laptop multimedia keys for volume and brightness into example config
2024-09-07 16:14:23 +01:00
outfoxxed
0500213086 input: try to refocus a focusable window when seat grabs are reset (#7669) 2024-09-07 01:06:55 +01:00
outfoxxed
b0fca6eaf0 input: kb focus mouse focused window if unset (#7666)
Normally it shouldn't be possible to have mouse focus with no kb
focus, but it does happen, and when it does this makes it considerably
less annoying.
2024-09-06 01:03:12 +01:00
Maximilian Seidler
4988e00b1d input: move idle notify to input handlers (#7659)
* Revert "input: don't emit idle activity when calling simulateMouseMovement (#7649)"

This reverts commit ea10592ad3.

* input: move idle notify calls to input event listeners

* input: don't post idle activity when keyboard is not enabled
2024-09-06 00:58:57 +01:00
Sungyoon Cho
0fad7a0bb0 workspacerules: fix on-created-empty window focus (#7657) 2024-09-06 00:54:01 +01:00
Sungyoon Cho
727f1b54cd textinput: fix ime activation in some edge cases (#7660)
* textinput: clear ti3 state when focused surface gets destroyed

* textinput: send enter to newly created ti in focus
2024-09-05 20:04:23 +01:00
Mihai Fufezan
c80457be02 nix: add COMMITS var 2024-09-05 21:26:12 +03:00
Parola Marco
4a42c5ed20 config: Add a variable to prevent groups from merging after being dragged (#7650)
* config: Add a variable to prevent groups from merging after being dragged

* Fixed code style for [f777f028]
2024-09-05 17:29:33 +01:00
trianta
bd6d6e7f33 xwayland: add option to enable/disable xwayland (#7633)
* config: add xwayland enabled option to config

* xwayland: use DISPLAY env variable for enable/disable of new launches

* xwayland: close X11 windows when turning of XWayland

* clang: format fix

* config: add better description for xwayland:enabled

* xwayland: close X11 windows on disable without crashes

* xwayland: better method of informing CXWayland if xwayland enabled

* xwayland: prevent closing non-xwayland windows on disable

* misc: loop formatting
2024-09-05 17:26:46 +01:00
Maximilian Seidler
027140b731 sessionLock: ensure sls focus in some edge cases (#7647)
* input: return early in mouseMoveUnified when the session is locked

* sessionLock: make make a commit an opportunity to focus session lock surfaces

* compositor: allow resetting focus when session is locked

* input: remove redundant PMONITOR checks

PMONITOR is checked above

* input: check isSessionLocked earlier in mouseMoveUnified

A bit of reordering, so that we don't call some stuff that is irrelevant
when the session is locked
2024-09-04 16:59:00 +01:00
Maximilian Seidler
ea10592ad3 input: don't emit idle activity when calling simulateMouseMovement (#7649) 2024-09-04 11:23:29 +01:00
vaxerski
9b54342baa Revert "syncobj: wait for deadline instead of available"
This reverts commit cf6a1716ae.

Fixes #7628
2024-09-03 14:47:34 +02:00
Mihai Fufezan
8f9887b0c9 Nix: remove unused dependencies 2024-09-02 23:48:58 +03:00
Jan Beich
fa39df4731 CMake: drop unused deps after 016da234d0
Found via LDFLAGS += -Wl,--as-needed (default in Meson).
Some dependencies are only used by aquamarine.
2024-09-02 23:48:58 +03:00
Jan Beich
f7249bd331 CMake: drop duplicate -luuid after 5262292abc 2024-09-02 23:48:58 +03:00
Sungyoon Cho
6934e7aa2b textinput: don't deactivate ime if another ti is focused (#7617) 2024-09-01 21:33:31 +02:00
Sungyoon Cho
8bbeee2041 textinput: send deactivate to ime on destory ti (#7614) 2024-09-01 18:44:33 +02:00
Mihai Fufezan
7a24e564f4 flake.lock: update xdph again 2024-09-01 19:37:25 +03:00
Mihai Fufezan
4b5b8a7630 flake.lock: update xdph 2024-09-01 18:14:14 +03:00
Mihai Fufezan
5b1375141b flake.lock: update 2024-09-01 17:18:57 +03:00
Tom Englund
4af9410dc2 xwm: read atom name from xcb (#7546)
expand the debug trace logging by actually reading the atom name from
xcb if not found in HYPRATOMS, will also print the proper atom for xcb
internal ones and not just the HYPRATOMS ones.
2024-09-01 12:04:28 +02:00
Ikalco
a6315b0af4 core: fix crash on monitor removed with gammaControl (#7601)
* fix crash on monitor removed with gammaControl

* Update GammaControl.cpp
2024-08-31 21:55:08 +02:00
TheMical
cac59fefec data-device: Fix selection mismatch when wlr resets primary selection (#7598) 2024-08-31 21:43:02 +02:00
Ikalco
1ac2fc3f7e protocols: destroy new xdgDialog protocol at right time (#7600) 2024-08-31 21:07:23 +02:00
Vaxry
cf6a1716ae syncobj: wait for deadline instead of available
avoids slow apps from lagging the desktop
2024-08-31 18:33:04 +02:00
NotAShelf
10d7219807 CI: clarify Nix CI jobs; disable on forked repositories 2024-08-31 17:17:36 +03:00
Ikalco
838ed87d6f renderer: minor direct scanout fixes (#7594) 2024-08-31 15:07:52 +02:00
Jan Beich
76b82fdde7 meson: explicitly specify path for find(1) (#7590)
assets/install/meson.build:1:10: ERROR: Command `/bin/sh -c 'find -type f -not -name "*.build"'` failed with status 1.
2024-08-31 11:01:02 +02:00
Vaxry
c5fd577181 config: Add a window rule to render while unfocused (#7582) 2024-08-30 17:37:52 +02:00
Vaxry
fbd6354393 presentation-feedback: minor fixups 2024-08-30 15:53:45 +02:00
Vaxry
fd8d8e122e keybinds: fixup misused kb state
fixes #7369
2024-08-30 15:53:45 +02:00
Vaxry
1c9d56998d xdg-dialog: implement new protocol 2024-08-30 15:53:44 +02:00
darkwater
242e06b242 keybinds: release mods after sendshortcut (#7581) 2024-08-30 15:06:49 +02:00
Vaxry
25e72949a1 window/xwayland: minor property cleanup
fixes #6921
2024-08-30 14:12:23 +02:00
trianta
259dcd838e xwayland: update overrideRedirect on map and configure (#7575) 2024-08-30 14:04:09 +02:00
Mihai Fufezan
ef33198e8f flake.lock: update aquamarine and hyprutils 2024-08-30 14:10:46 +03:00
Vaxry
604eb21a7e renderer: better lockscreen dead behavior (#7574)
---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-08-29 23:30:12 +02:00
Mihai Fufezan
92a0dd164e flake.lock: update 2024-08-29 13:41:03 +00:00
Vaxry
b9b8e6220f renderer: fade out windows on silent moves 2024-08-28 21:54:49 +02:00
Vaxry
a95df6b57e xwm: don't mark selection events as succeeded
fixes #7401
2024-08-28 20:37:07 +02:00
Vaxry
9642311ac2 window: don't focus on activate if window isn't mapped yet
ref #7089
2024-08-28 20:33:38 +02:00
Ikalco
98e99cd03d renderer: ensure buffer format on commit (#7556) 2024-08-28 15:07:13 +02:00
diniamo
8210a1d7ac nix(flake): update aquamarine 2024-08-28 15:28:01 +03:00
Vaxry
d105c7403c hyprctl: add next and all to switchxkblayout
fixes #7555
2024-08-28 14:05:31 +02:00
Vaxry
00ee1cf98e data-device: send dndFinished when dnd offer is destroyed while unfinished
fixes #7496

see 711c5bb43f

see https://bugs.kde.org/show_bug.cgi\?id\=482142
2024-08-28 13:45:13 +02:00
Ikalco
7dd0f76e5a logs: don't get timezone every time logging (#7550)
its expensive cause cpp dum
2024-08-28 13:19:06 +02:00
Tom Englund
17ed4fc04c hyprctl: avoid parsing string::npos on invalid cmd (#7544)
* hyprctl: avoid parsing string::npos on invalid cmd

invalid lines passed to hyprctl keyword made the string parsing try to
parse std::string::npos, avoid that and return an error text instead.

* style

---------

Co-authored-by: Vaxry <vaxry@vaxry.net>
2024-08-27 20:42:30 +02:00
Nick H
6a8824253c build: Fix NO_XWAYLAND compilation (#7538) 2024-08-27 20:41:46 +02:00
Serenity Braesch
eb42adc4c0 Fix missing include needed by clang 2024-08-26 22:36:43 +03:00
raf
09dbcabcc7 CI: disable stale workflow on forks (#7535)
The stale workflow will run unconditionally, but will fail on forks due to
`STALEBOT_PAT` not being set. Trigger the workflow *only* if we are on the
main repo, where we can guarantee the PAT. Also formats the YML syntax to be
slightly more readable.
2024-08-26 20:24:57 +02:00
Tom Englund
72c7818ae6 misc: constify the remaining for loops (#7534)
now we roll loops at blazing constified speed.
2024-08-26 20:24:30 +02:00
Tom Englund
1ea47950f4 misc: fix some minor typos (#7530)
* keybindmgr: fix typo in swap prev

seems a suspicious extra ) got added, remove it.

* configmgr: dont dereference invalid iterator

i think the idea here was to print the key and not the iterator at or
past .end()
2024-08-26 18:02:44 +02:00
Tom Englund
8d6c18076f core: make most for loops use const references (#7527)
why not let the compiler optimise things for us at hyprspeeds when we
can.
2024-08-26 17:25:39 +02:00
Tom Englund
9c5a37a797 build: fix 32bit builds (#7510)
ensure the correct type is passed to std::clamp and std::max int64_t is
different on 64bit compared to 32bit, also in presentationtime
tv_sec is __time_t and on 32bit its a 32bit type so right shift count >= width
of type. so only bit shift on 64bit. and avoid potential nullptr deref
in the for loops, check for .end() before *it <= endID.
2024-08-26 14:08:30 +02:00
Adithya Ajith
ca85455a8e misc: Rename all instances of "emtpy" to "empty" (#7522) 2024-08-26 12:25:52 +02:00
Maximilian Seidler
28f6c2df59 sessionLock: fix misc:allow_session_lock_restore (#7511)
* Revert "sessionLock: fix the check for locking a locked session (#6843)"

This reverts commit 9ff83f4aa9.

* sessionLock: remove early check for session beeing locked

It is checked in the `onNewSessionLock` handler, which also respects the
`misc:allow_session_lock_restore` option.
2024-08-26 10:27:34 +02:00
Vaxry
83ab3ae0af xwaylandmgr: minor refactor to activateSurface
Make it more efficient now that we can + fix possible nullptr deref

fixes #7514
2024-08-26 10:24:45 +02:00
trianta
b672118f92 xwayland: deactivate xwayland focus if wayland is focused (#7458)
* xwayland: deactivate xwayland focus if wayland is focused

* xwayland: deactivate last xwayland surface after focusing wayland
2024-08-25 16:37:03 +02:00
Nelo-T. Wallus
aac90d9279 hyprpm: Fix checking dependencies (#7504)
* hyprpm: Fix checking dependencies

* hyprpm: Check for dependency "pkg-config"

---------

Co-authored-by: Nelo-T. Wallus <nelo@wallus.de>
2024-08-25 13:13:48 +02:00
Ikalco
66586c38f5 keybinds: refactor dispatchers to be better (#7331) 2024-08-24 18:45:53 +02:00
Vaxry
82c67e61a9 config: fix uninitialized values with mode parsing 2024-08-24 15:24:55 +02:00
Vaxry
e45e606fbd layersurface: don't unref from monitor until dtor
reee
2024-08-24 15:22:10 +02:00
Sungyoon Cho
688fe5c147 windowrules: add fullscreenstate field (#7466)
* windowrules: add fullscreenstate field

* fix typo
2024-08-23 20:42:14 +01:00
MahouShoujoMivutilde
a3b75559b3 input: Fix modifier keys getting stuck if depressed during config reload (#7486)
The problem:
    If `input:numlock_by_default = true`, depressed mods will get stuck
    on config reload; this takes effect after some other mod is pressed.

This restores 0.41.2 behavior, with the exception that selected keyboard
layout is preserved.

918d8340af/src/managers/input/InputManager.cpp (L993-L1002)
2024-08-23 20:35:52 +01:00
Tom Englund
df4f222482 layersurface: remove layer on destroy from monitor (#7457)
remove destroyed layer weakptrs on destroy, we can hit multiple
null ptr derefs in renderering on mirroring and unmirroring displays
otherwise.
2024-08-23 14:06:52 +01:00
vaxerski
3b663f4afc screencopy: fixup 10-bit sharing via shm on nvidia 2024-08-23 14:13:49 +02:00
Red
f634b9e61a Fix crash reports having execute permission 2024-08-22 15:28:01 +03:00
Mihai Fufezan
bdb296a83c flake.lock: update 2024-08-22 14:30:17 +03:00
Mihai Fufezan
4fa63104c9 Nix: exclude wayland-scanner until next staging merge 2024-08-22 14:30:10 +03:00
Florian Klink
a437e44a6a CMakeLists: wayland.xml is in wayland-scanner pkgdatadir
See 6c4a695045/meson.build (L129-136)

Similar fix as https://github.com/hyprwm/aquamarine/pull/55.
2024-08-22 13:50:00 +03:00
Tom Englund
cae937c51b layersurface: dont rollover on size_t (#7451)
unneded rollover on size_t if force equals -1
2024-08-21 22:05:03 +01:00
James R Larrowe
8162fae377 Fix Makefile too
... did this ever work?
2024-08-21 23:09:13 +03:00
James R Larrowe
c5786be695 Fix static asan patch 2024-08-21 23:09:13 +03:00
Mihai Fufezan
1b1ecf77e0 Nix: include xcursor regardless of xwayland 2024-08-21 22:37:28 +03:00
vaxerski
883463f9dd animations: add workspace in/out configs 2024-08-21 14:38:07 +02:00
Tom Englund
3e7325af57 output: dont cast enum out of range (#7448)
avoid casting non typed enum out of range, looks like
WL_OUTPUT_MODE_CURRENT was the intention here.
2024-08-21 11:52:40 +01:00
ParaN3xus
946ed1f32a core: add option to control which window to focus on close (#7368) 2024-08-21 11:24:42 +01:00
Ali Atashrooz
4eff224a7f example/config: fix typo in default config (#7446)
* Update hyprland.conf

* Update defaultConfig.hpp
2024-08-21 11:24:02 +01:00
vaxerski
c86db7bbb0 monitor: avoid dangling references to old monitors being undestroyed
ref #7414
2024-08-19 18:44:22 +02:00
vaxerski
272d904870 monitors: avoid crash on wayland output removal 2024-08-19 18:36:14 +02:00
JL2210
01e3da4d51 examples: more systemd examples (#7409)
These allow launching hyprland with a systemd service. They provide
graphical-session.target which allows enabling services such as the
ones for Waybar and Mako.
2024-08-19 14:02:09 +01:00
Jan Beich
33015546c6 config: add missing header for libc++ after 92744b5b9a (#7403)
In file included from src/pch/pch.hpp:1:
In file included from src/Compositor.hpp:11:
src/config/ConfigManager.hpp:147:10: error: no template named 'variant' in namespace 'std'
  147 |     std::variant<SBoolData, SRangeData, SFloatData, SStringData, SColorData, SChoiceData, SGradientData, SVectorData> data;
      |     ~~~~~^
2024-08-19 13:46:36 +01:00
loseardes77
83d88fa564 hyprpm, hyprctl: update shell completions 2024-08-19 00:21:59 +03:00
diniamo
11dfb8397b flake: update aquamarine 2024-08-19 00:18:26 +03:00
vaxerski
f4045ab8d0 screencopy: fix 10b format r/b flip 2024-08-18 22:57:21 +02:00
vaxerski
fa12efdd2a protocol: fix logm template checks 2024-08-18 22:54:47 +02:00
vaxerski
bf611fbbf3 screencopy: nuke unused stuff 2024-08-18 22:40:21 +02:00
Tom Englund
5afc4dc42e compositor: update suspendstate on window move (#7396)
hyprctl dispatch -- movetoworkspacesilent x,"^kitty$" where X is the
current workspace makes kitty stops updating until current workspace is
changed while it is on the screen. update the suspend state after it has
been moved.
2024-08-18 20:02:46 +01:00
vaxerski
50348a3ddb renderer: pass custom modelines to aq
ref #7390
2024-08-18 20:19:13 +02:00
vaxerski
279ec1c291 linux-dmabuf: allow on split-node systems
ref #7364
2024-08-18 19:52:01 +02:00
Tom Englund
1006663b6e shm: align size to stride (#7383)
calculate the size to the stride we got to better align it.
2024-08-18 09:23:27 +01:00
Sami Liedes
b2a18aa80a input: Fix disabling tap-to-click (#7304)
* Allow disabling tap-to-click

* Style fix
2024-08-18 08:14:42 +01:00
leiserfg
d21a6b12b8 Update aquamarine input in flake 2024-08-18 09:47:39 +03:00
vaxerski
912e7ba82d render: fixup format mismatch after leaving DS
fixes #7373
2024-08-17 19:27:20 +02:00
Vaxry
92744b5b9a IPC: Add config descriptions (#7377)
Thanks @gulafaran for the work

---

Co-authored-by: @gulafaran
2024-08-17 17:33:16 +01:00
Tom Englund
c5feee1e35 xcursormgr: dont apply scale on gsettings (#7316)
gtk scales the cursor size itself since its CSD so if we scale the size
its gonna get double scaled. incorporate the scale into xcursormanager
to keep track of it.
2024-08-16 17:00:59 +01:00
Tom Englund
1840a907a8 renderbuffer: ensure framebuffer gets deleted (#7363)
after commit 4b4971c it uses m_iFbAllocated and deletes if upon calling
release() but Renderbuffer generates directly on m_iFb without calling
alloc() meaning it wont be deleted on release(), set m_iFbAllocated to
true after generating the buffer.
2024-08-16 10:09:01 +01:00
Vladimir-csp
682b30fba8 env: Add HYPRLAND_NO_SD_VARS env condition (#7358)
* Add HYPRLAND_NO_SD_VARS env condition

wip #7083

* Formatting shuffle

* Formatting
2024-08-16 08:19:08 +01:00
Tom Englund
12d9901472 protocols: refactor protocol logging to a macro (#7324)
this avoids the usage of the unique_ptr PROTO::protocol before it has
been constructed incase one wants to log something inside the
constructor itself, move the logging to macros and print file:linenumber
on ERR,CRIT,WARN and classname on the rest of the levels.
2024-08-15 17:16:18 +01:00
Vladimir-csp
15f942000e core: Preserve existing XDG_CURRENT_DESKTOP (#7347)
* Preserve existing XDG_CURRENT_DESKTOP

* fix

---------

Co-authored-by: vaxerski <vaxry@vaxry.net>
2024-08-15 17:14:48 +01:00
Maximilian Seidler
520e91238f gamma-control: fix crash on monitor disconnect (#7353) 2024-08-15 17:08:54 +01:00
Kyle
0c56be74a3 keybinds: Fix syncFullscreen inconsistent with state when set by fullscreenState (#7343)
* Set syncFullscreen to true on synced non -1 states

* Fix syncFullscreen value in fullscreenState
2024-08-15 17:04:24 +01:00
Mirkwood
069faa4027 helpers: fix: revert to signed arithmetic for cycling through workspaces (#7339)
The code clearly expects signed types there.
Fixes #7329
2024-08-15 13:03:23 +01:00
vaxerski
c30dfe92ee [gha] Nix: update inputs 2024-08-15 11:39:29 +00:00
Ikalco
d85ae306c5 xcursor: handle file errors when loading xcursor themes (#7326) 2024-08-15 12:37:56 +01:00
davc0n
197f880790 logs: Add file path to asset ERR log (#7336) 2024-08-14 18:35:07 +01:00
MightyPlaza
3b4aabe04c decorations: fix manual resize not recalculating decos (#7323)
modified:   src/layout/DwindleLayout.cpp
modified:   src/layout/MasterLayout.cpp
2024-08-13 21:00:31 +01:00
Mihai Fufezan
c5ec079c6f hyprpm, hyprctl: remove Makefiles 2024-08-13 22:14:58 +03:00
Patrick Ulbricht
4aec237ec0 README: Change image sources from vaxerski/Hyprland to hyprwm/Hyprland (#7315)
* readme: Change image sources from vaxerski/Hyprland to hyprwm/Hyprland

* readme: Remove unused image
2024-08-13 19:14:52 +01:00
Ikalco
39df1f4dbf cursormgr: fix cursor gsettings on session change (#7295) 2024-08-13 18:27:00 +01:00
Tom Englund
77cf651825 protocols: avoid crashing in drmlease (#7290)
instead of potentially causing wonky behaviour from destructing in the
constructor add the unique_ptr reset to doLater and dont use the not
done constructed protolog in the constructor, call Debug::log directly.

see issue #7240
2024-08-12 19:49:52 +01:00
Kyle
c7b72790bd keybinds: Fix fullscreenState toggling behaviour (#7288)
* Update fullscreen state dispatcher behaviour

* Change syncFullscreen default to false

* Revert all changes

* Modify fullscreenstate dispatcher toggle behaviour

* Update syncFullscreen according to state

* Update syncFullscreen before setting fullscreen state
2024-08-12 18:41:26 +01:00
Tom Englund
3fa6db1e7a core: fix data race and a unsigned int rollover (#7278)
* keybindmgr: avoid uint rollover on mouse keycode

mouse keycode is 0, and the switch case checks for 0 - 8 and rolls over,
just return early if keycode is 0.

* watchdog: avoid data races in watchdog

asan thread sanitizer reported data races in the watchdog from reading
and setting the bool variables make them std::atomic bools. also add a
atomic bool for the main thread to wait for to avoid data race when
reading the config values.

* hyprdebug: change non unicode character to name

asan created false positives and didnt like this bit, so for the sake of
easier debugging rename it to something unicode.
2024-08-12 18:19:03 +01:00
Ikalco
d361fcbd85 config: fix explicit sync option warning (#7293) 2024-08-12 17:16:00 +01:00
Mihai Fufezan
df9d830117 flake.lock: update 2024-08-12 18:18:03 +03:00
Yang, Ying-chao
118d4e1001 install: Prepend ${DESTDIR} when creating hyprland symbolic link (fixes #7280). (#7281) 2024-08-11 20:38:16 +01:00
Tom Englund
511eea71c6 pointermgr: fix initial cursorwarp (#7286)
change the hook to monitorAdded instead of newMonitor so its finalized
in the compositor and added to vMonitors, move the
checkDefaultCursorWarp to PointerManager and check for it upon mode
change. and also ensure it doesnt go out of bounds by replacing it in
the middle again on resolution changes.
2024-08-11 19:42:18 +01:00
Walt Bringenberg
01ff5fdf6a cursor: make inactive_timeout setting a float (#7268) 2024-08-10 21:42:45 +01:00
Zach DeCook
0bf9ceb53b core: Include cstring whenever strncpy is used (#7267)
Fixes ppc64le build in alpine
2024-08-10 21:09:12 +01:00
Vaxry
4fdc0d55e4 eventloop: don't dispatch in enterLoop
ref #6842, BSD blocks in udev on no event apparently
2024-08-10 00:04:26 +02:00
Tom Englund
8b37e81374 cursormgr: add a new setting to sync gsettings (#7253)
cursor:sync_gsettings_theme is set to default true and if enabled it
will now sync xcursor theme loading with gsettings if it can, meaning
CSD clients will now also change to the appropiate theme upon start and
hyprctl setcursor THEME SIZE .
2024-08-09 19:33:20 +02:00
Mathis H.
fd1d4e288e headers: set correct paths to header files (#7245) 2024-08-09 16:51:21 +02:00
Tom Englund
4b4971c06f internal: introduce new types to avoid unsigned int rollover and signed int overflow (#7216)
* framebuffer: avoid gluint overflow

GLuint was being initialized to -1 and rolling over to unsigned int max,
its defined behaviour but very unnecessery. add a bool and use it for
checking if allocated or not.

* opengl: avoid gluint rollover

-1 rolls over to unsigned int max, use 0xFF instead.

* core: big uint64_t to int type conversion

there were a few uint64_t to int implicit conversions overflowing int
and causing UB, make all monitor/workspaces/windows use the new
typedefs. also fix the various related 64 to 32 implicit conversions
going around found with -Wshorten-64-to-32
2024-08-08 21:01:50 +02:00
Vaxry
83a334f97d core: Move to C++26 and use native_handle to CLOEXEC the debug fd (#7219)
Requires GCC >= 14 / Clang >= 18

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
2024-08-08 11:54:41 +02:00
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
339 changed files with 17474 additions and 11791 deletions

View File

@@ -2,21 +2,25 @@ name: Bug Report
description: Something is not working right
labels: ["bug"]
body:
- type: markdown
- type: checkboxes
attributes:
value: |
Before opening a new issue, take a moment to search through the current open ones.
---
label: Already reported ? *
description: Before opening a new bug report, please take a moment to search through the current open and closed issues to check if it already exists.
options:
- label: I have searched the existing open and closed issues.
required: true
- type: dropdown
id: type
attributes:
label: Bug or Regression?
description: Is this a bug or a regression?
label: Regression?
description: |
Regression means that something used to work but no longer does.
**BEFORE CONTINUING**, please check if this bug is a regression or not, and if it is, we need you to bisect with the help of the wiki: https://wiki.hyprland.org/Crashes-and-Bugs/#bisecting-an-issue
multiple: true
options:
- Bug
- Regression
- "Yes"
- "No"
validations:
required: true
@@ -25,10 +29,10 @@ body:
attributes:
label: System Info and Version
description: |
Paste the output of `hyprctl systeminfo -c` here (If you are on a
version that shows you help menu, omit the `-c` and attach config files
to the issue). If you have configs outside of the main config shown
here, please attach.
Paste the output of `hyprctl systeminfo -c` here. If you can't
launch Hyprland, paste the output of `Hyprland --systeminfo`.
If `Hyprland --systeminfo` errors out (added in 0.44.0), find
and paste the Hyprland version manually.
value: "<details>
<summary>System/Version info</summary>

View File

@@ -34,6 +34,7 @@ runs:
libglvnd \
libinput \
libliftoff \
libxcursor \
libxcvt \
libxfont2 \
libxkbcommon \
@@ -68,6 +69,16 @@ runs:
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
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
shell: bash
if: inputs.INSTALL_XORG_PKGS == 'true'

View File

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

View File

@@ -1,3 +1,5 @@
name: Nix (Build)
on:
workflow_call:
secrets:
@@ -10,21 +12,17 @@ jobs:
matrix:
package:
- hyprland
- hyprland-cross
- xdg-desktop-portal-hyprland
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
with:
ref: ${{ github.ref }}
submodules: recursive
- uses: cachix/install-nix-action@v26
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v12
- uses: cachix/cachix-action@v15
with:
name: hyprland
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"
- run: nix build 'github:hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"

View File

@@ -1,15 +1,14 @@
name: Nix
name: Nix (CI)
on: [push, pull_request, workflow_dispatch]
jobs:
update-inputs:
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
uses: ./.github/workflows/nix-update-inputs.yml
secrets: inherit
build:
if: always() && !cancelled() && !contains(needs.*.result, 'failure')
needs: update-inputs
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
uses: ./.github/workflows/nix-build.yml
secrets: inherit

View File

@@ -1,4 +1,4 @@
name: Nix
name: Nix (Update Inputs)
on:
workflow_call:
@@ -8,6 +8,7 @@ on:
jobs:
update:
if: github.repository == 'hyprwm/Hyprland'
name: inputs
runs-on: ubuntu-latest
steps:

View File

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

View File

@@ -7,12 +7,12 @@ name: Mark stale issues and pull requests
on:
schedule:
- cron: '7 */4 * * *'
- cron: "7 */4 * * *"
workflow_dispatch:
jobs:
stale:
if: github.repository == 'hyprwm/Hyprland'
runs-on: ubuntu-latest
permissions:
issues: write
@@ -22,7 +22,7 @@ jobs:
- uses: actions/stale@v5
with:
repo-token: ${{ secrets.STALEBOT_PAT }}
stale-issue-label: 'stale'
stale-pr-label: 'stale'
stale-issue-label: "stale"
stale-pr-label: "stale"
operations-per-run: 40
days-before-close: -1

10
.gitignore vendored
View File

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

4
.gitmodules vendored
View File

@@ -7,7 +7,3 @@
[submodule "subprojects/tracy"]
path = subprojects/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)
include(CheckIncludeFile)
include(ExternalProject)
include(GNUInstallDirs)
cmake_minimum_required(VERSION 3.30)
# Get version
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/props.json PROPS)
string(JSON VER GET ${PROPS} version)
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
string(STRIP ${VER_RAW} VER)
project(Hyprland
project(
Hyprland
DESCRIPTION "A Modern C++ Wayland Compositor"
VERSION ${VER}
)
VERSION ${VER})
include(CheckIncludeFile)
include(GNUInstallDirs)
set(HYPRLAND_VERSION ${VER})
set(PREFIX ${CMAKE_INSTALL_PREFIX})
@@ -22,17 +21,22 @@ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
message(STATUS "Gathering git info")
# Get git info
# hash and branch
execute_process(
COMMAND ./scripts/generateVersion.sh
# Get git info hash and branch
execute_process(COMMAND ./scripts/generateVersion.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# udis
add_subdirectory("subprojects/udis86")
find_package(PkgConfig REQUIRED)
# wlroots
message(STATUS "Setting up wlroots")
# Try to find canihavesomecoffee's udis86 using pkgconfig vmd/udis86 does not
# provide a .pc file and won't be detected this way
pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2)
# Fallback to subproject
if(NOT udis_dep_FOUND)
add_subdirectory("subprojects/udis86")
include_directories("subprojects/udis86")
message(STATUS "udis86 dependency not found, falling back to subproject")
endif()
if(CMAKE_BUILD_TYPE)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
@@ -53,25 +57,11 @@ else()
set(BUILDTYPE_LOWER "release")
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)
pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner)
message(STATUS "Found WaylandScanner at ${WaylandScanner}")
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir)
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
message(
STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}")
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Configuring Hyprland in Debug with CMake")
@@ -81,17 +71,17 @@ else()
message(STATUS "Configuring Hyprland in Release with CMake")
endif()
include_directories(
.
"src/"
"subprojects/wlroots-hyprland/include/"
"subprojects/wlroots-hyprland/build/include/"
"subprojects/udis86/"
"protocols/")
set(CMAKE_CXX_STANDARD 23)
add_compile_definitions(WLR_USE_UNSTABLE)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value
-Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith
include_directories(. "src/" "protocols/")
set(CMAKE_CXX_STANDARD 26)
add_compile_options(
-Wall
-Wextra
-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)
@@ -108,13 +98,32 @@ else()
endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(deps REQUIRED IMPORTED_TARGET
xkbcommon uuid
wayland-server wayland-client wayland-cursor wayland-protocols
cairo pango pangocairo pixman-1
libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm
hyprlang>=0.3.2 hyprcursor>=0.1.7
)
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1)
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine)
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
pkg_check_modules(
deps
REQUIRED
IMPORTED_TARGET
xkbcommon
uuid
wayland-server>=1.22.90
wayland-protocols
cairo
pango
pangocairo
pixman-1
xcursor
libdrm
libinput
gbm
gio-2.0
hyprlang>=0.3.2
hyprcursor>=0.1.7
hyprutils>=0.2.3)
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
@@ -127,14 +136,13 @@ if(USE_TRACY)
endif()
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
add_dependencies(Hyprland wlroots-hyprland)
set(USE_GPROF ON)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Setting debug flags")
if (WITH_ASAN)
if(WITH_ASAN)
message(STATUS "Enabling ASan")
target_link_libraries(Hyprland asan)
@@ -144,9 +152,9 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
if(USE_TRACY)
message(STATUS "Tracy is turned on")
option( TRACY_ENABLE "" ON)
option( TRACY_ON_DEMAND "" ON)
add_subdirectory (subprojects/tracy)
option(TRACY_ENABLE "" ON)
option(TRACY_ON_DEMAND "" ON)
add_subdirectory(subprojects/tracy)
target_link_libraries(Hyprland Tracy::TracyClient)
@@ -192,7 +200,17 @@ if(NO_XWAYLAND)
add_compile_definitions(NO_XWAYLAND)
else()
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(
xdeps
REQUIRED
IMPORTED_TARGET
xcb
xcb-render
xcb-xfixes
xcb-icccm
xcb-composite
xcb-res
xcb-errors)
target_link_libraries(Hyprland PkgConfig::xdeps)
endif()
@@ -209,113 +227,112 @@ include(CPack)
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")
target_link_libraries(Hyprland rt PkgConfig::deps)
target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps)
if(udis_dep_FOUND)
target_link_libraries(Hyprland PkgConfig::udis_dep)
else()
target_link_libraries(Hyprland libudis86)
endif()
# used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers)
function(protocol 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}-protocol.h
COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c
COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
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})
function(protocolnew protoPath protoName external)
if(external)
set(path ${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)
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()
function(protocolWayland)
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
COMMAND
hyprwayland-scanner --wayland-enums
${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
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()
target_link_libraries(Hyprland
${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a
OpenGL::EGL
OpenGL::GL
Threads::Threads
libudis86
uuid
)
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true)
protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true)
protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true)
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0)
if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
else()
set(HYPRLAND_PROTOCOLS "subprojects/hyprland-protocols")
message(STATUS "hyprland-protocols subproject set to ${HYPRLAND_PROTOCOLS}")
endif()
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("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1"
true)
protocolnew("unstable/text-input" "text-input-unstable-v1" false)
protocolnew("${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("${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("staging/xdg-dialog" "xdg-dialog-v1" false)
protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
protocolWayland()
protocolwayland()
# tools
add_subdirectory(hyprctl)
@@ -324,60 +341,54 @@ add_subdirectory(hyprpm)
# binary and symlink
install(TARGETS Hyprland)
install(CODE "execute_process( \
install(
CODE "execute_process( \
COMMAND ${CMAKE_COMMAND} -E create_symlink \
${CMAKE_INSTALL_BINDIR}/Hyprland \
${CMAKE_INSTALL_BINDIR}/hyprland
)"
)
${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
\"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \
)")
# session file
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
DESTINATION ${CMAKE_INSTALL_DATADIR}/wayland-sessions)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
# wallpapers
file(GLOB_RECURSE WALLPAPERS "assets/wall*")
install(FILES ${WALLPAPERS}
DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland)
# allow Hyprland to find assets
add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}")
# installable assets
file(GLOB_RECURSE INSTALLABLE_ASSETS "assets/install/*")
list(FILTER INSTALLABLE_ASSETS EXCLUDE REGEX "meson.build")
install(FILES ${INSTALLABLE_ASSETS}
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
# default config
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf
DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland)
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
# portal config
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
file(GLOB_RECURSE MANPAGES "docs/*.1")
install(FILES ${MANPAGES}
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
install(FILES ${MANPAGES} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
# pkgconfig entry
install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc
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
set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols")
install(DIRECTORY ${HEADERS_PROTO}
install(
DIRECTORY ${HEADERS_PROTO}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING PATTERN "*.h*")
FILES_MATCHING
PATTERN "*.h*")
# hyprland headers
set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src")
install(DIRECTORY ${HEADERS_SRC}
install(
DIRECTORY ${HEADERS_SRC}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
FILES_MATCHING PATTERN "*.h*")
FILES_MATCHING
PATTERN "*.h*")

View File

@@ -1,33 +1,28 @@
PREFIX = /usr/local
legacyrenderer:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all
chmod -R 777 ./build
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./buildZ
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
legacyrendererdebug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all
chmod -R 777 ./build
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
release:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all
chmod -R 777 ./build
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
debug:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all
chmod -R 777 ./build
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
nopch:
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build -G Ninja
cmake --build ./build --config Release --target all
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
clear:
rm -rf build
rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp
rm -rf ./subprojects/wlroots-hyprland/build
all:
$(MAKE) clear
@@ -50,14 +45,11 @@ installheaders:
rm -fr ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland/protocols
mkdir -p ${PREFIX}/include/hyprland/wlr
mkdir -p ${PREFIX}/share/pkgconfig
cmake --build ./build --config Release --target generate-protocol-headers
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 ./build/hyprland.pc ${PREFIX}/share/pkgconfig
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
@@ -88,11 +80,11 @@ asan:
@pidof Hyprland > /dev/null && exit 1 || echo ""
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"
@read patchvar
@if [-n "$patchvar"]; then patch -p1 < $patchvar || echo ""; else echo "No patch specified"; fi
@read patchvar; \
if [ -n "$$patchvar" ]; then patch -p1 < "$$patchvar" || echo ""; else echo "No patch specified"; fi
git clone --recursive https://gitlab.freedesktop.org/wayland/wayland
cd wayland && patch -p1 < ../scripts/waylandStatic.diff && meson setup build --buildtype=debug -Db_sanitize=address -Ddocumentation=false && ninja -C build && cd ..

View File

@@ -1,6 +1,6 @@
<div align = center>
<img src="https://raw.githubusercontent.com/vaxerski/Hyprland/main/assets/header.svg" width="750" height="300" alt="banner">
<img src="https://raw.githubusercontent.com/hyprwm/Hyprland/main/assets/header.svg" width="750" height="300" alt="banner">
<br>
@@ -13,10 +13,10 @@
<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,
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>
@@ -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
- 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
- Powerful plugin support
- 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
- Fully dynamic workspaces
- Two built-in layouts and more available as plugins
- Uses forked wlroots with QoL patches
- Global keybinds passed to your apps of choice
- Tiling/pseudotiling/floating/fullscreen windows
- Special workspaces (scratchpads)
@@ -86,7 +85,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
<br>
**[wlroots]** - *For their amazing library*
**[wlroots]** - *For powering Hyprland in the past*
**[tinywl]** - *For showing how 2 do stuff*
@@ -126,7 +125,6 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
<!----------------------------------{ Images }--------------------------------->
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
[Preview A]: https://i.ibb.co/C1yTb0r/falf.png
[Preview B]: https://linfindel.github.io/cdn/hyprland-preview-b.png
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png

1
VERSION Normal file
View File

@@ -0,0 +1 @@
0.44.1

BIN
assets/install/lockdead.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1,10 @@
globber = run_command('sh', '-c', 'find . -type f -not -name "*.build"', check: true)
files = globber.stdout().strip().split('\n')
foreach file : files
install_data(
file,
install_dir: join_paths(get_option('datadir'), 'hypr'),
install_tag: 'runtime',
)
endforeach

View File

Before

Width:  |  Height:  |  Size: 14 MiB

After

Width:  |  Height:  |  Size: 14 MiB

View File

Before

Width:  |  Height:  |  Size: 5.9 MiB

After

Width:  |  Height:  |  Size: 5.9 MiB

View File

Before

Width:  |  Height:  |  Size: 27 MiB

After

Width:  |  Height:  |  Size: 27 MiB

View File

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

View File

@@ -10,8 +10,8 @@ Hyprland - Dynamic tiling Wayland compositor
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
.SH DESCRIPTION
.PP
\f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on
wlroots that doesn\[aq]t sacrifice on its looks.
\f[B]Hyprland\f[R] is an independent, highly customizable, dynamic
tiling Wayland compositor that doesn\[aq]t sacrifice on its looks.
.PP
You can launch Hyprland by either going into a TTY and executing
\f[B]Hyprland\f[R], or with a login manager.
@@ -32,6 +32,12 @@ Show command usage.
.TP
\f[B]-c\f[R], \f[B]--config\f[R]
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
.TP
Submit bug reports and request features online at:

View File

@@ -14,8 +14,8 @@ SYNOPSIS
DESCRIPTION
===========
**Hyprland** is a dynamic tiling Wayland compositor based on
wlroots that doesn't sacrifice on its looks.
**Hyprland** is an independent, highly customizable,
dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
You can launch Hyprland by either going into a TTY and
executing **Hyprland**, or with a login manager.
@@ -41,6 +41,12 @@ OPTIONS
**-c**, **--config**
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
====

View File

@@ -1,2 +1,2 @@
install_man ('Hyprland.1')
install_man ('hyprctl.1')
install_man('Hyprland.1')
install_man('hyprctl.1')

View File

@@ -0,0 +1,14 @@
[Unit]
Description=Hyprland - Tiling compositor with the looks
Documentation=man:Hyprland(1)
BindsTo=graphical-session.target
Before=graphical-session.target
Wants=graphical-session-pre.target
After=graphical-session-pre.target
[Service]
Type=notify
ExecStart=/usr/bin/Hyprland
ExecStop=/usr/bin/hyprctl dispatch exit
Restart=on-failure
Slice=session.slice

View File

@@ -0,0 +1,5 @@
[Desktop Entry]
Name=Hyprland
Comment=An intelligent dynamic tiling Wayland compositor
Exec=systemctl --user start --wait hyprland-session
Type=Application

View File

@@ -125,7 +125,7 @@ dwindle {
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
master {
new_is_master = true
new_status = master
}
# https://wiki.hyprland.org/Configuring/Variables/#misc
@@ -169,9 +169,9 @@ device {
}
####################
### KEYBINDINGSS ###
####################
###################
### KEYBINDINGS ###
###################
# See https://wiki.hyprland.org/Configuring/Keywords/
$mainMod = SUPER # Sets "Windows" key as main modifier
@@ -228,6 +228,19 @@ bind = $mainMod, mouse_up, workspace, e-1
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next
bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous
##############################
### WINDOWS AND WORKSPACES ###
@@ -242,4 +255,8 @@ bindm = $mainMod, mouse:273, resizewindow
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
# Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0

View File

@@ -1,2 +1,10 @@
install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), 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',
)

125
flake.lock generated
View File

@@ -1,5 +1,34 @@
{
"nodes": {
"aquamarine": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"hyprwayland-scanner": [
"hyprwayland-scanner"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1727261104,
"narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "b82fdaff917582a9d568969e15e61b398c71e990",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "aquamarine",
"type": "github"
}
},
"hyprcursor": {
"inputs": {
"hyprlang": [
@@ -13,11 +42,11 @@
]
},
"locked": {
"lastModified": 1717181720,
"narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=",
"lastModified": 1727532803,
"narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c",
"rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f",
"type": "github"
},
"original": {
@@ -27,6 +56,29 @@
}
},
"hyprland-protocols": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1727451107,
"narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprland-protocols",
"type": "github"
}
},
"hyprland-protocols_2": {
"inputs": {
"nixpkgs": [
"xdph",
@@ -38,11 +90,11 @@
]
},
"locked": {
"lastModified": 1691753796,
"narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=",
"lastModified": 1721326555,
"narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03",
"rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84",
"type": "github"
},
"original": {
@@ -53,6 +105,9 @@
},
"hyprlang": {
"inputs": {
"hyprutils": [
"hyprutils"
],
"nixpkgs": [
"nixpkgs"
],
@@ -61,11 +116,11 @@
]
},
"locked": {
"lastModified": 1716473782,
"narHash": "sha256-+qLn4lsHU6iL3+HTo1gTQ1tWzet8K9h+IfVemzEQZj8=",
"lastModified": 1725997860,
"narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "87d5d984109c839482b88b4795db073eb9ed446f",
"rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876",
"type": "github"
},
"original": {
@@ -74,6 +129,29 @@
"type": "github"
}
},
"hyprutils": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1727300645,
"narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=",
"owner": "hyprwm",
"repo": "hyprutils",
"rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprutils",
"type": "github"
}
},
"hyprwayland-scanner": {
"inputs": {
"nixpkgs": [
@@ -84,11 +162,11 @@
]
},
"locked": {
"lastModified": 1717784906,
"narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=",
"lastModified": 1726874836,
"narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
"rev": "0f30f9eca6e404130988554accbb64d1c9ec877d",
"rev": "500c81a9e1a76760371049a8d99e008ea77aa59e",
"type": "github"
},
"original": {
@@ -99,11 +177,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1717602782,
"narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=",
"lastModified": 1727348695,
"narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6",
"rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
"type": "github"
},
"original": {
@@ -115,8 +193,11 @@
},
"root": {
"inputs": {
"aquamarine": "aquamarine",
"hyprcursor": "hyprcursor",
"hyprland-protocols": "hyprland-protocols",
"hyprlang": "hyprlang",
"hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner",
"nixpkgs": "nixpkgs",
"systems": "systems",
@@ -140,10 +221,16 @@
},
"xdph": {
"inputs": {
"hyprland-protocols": "hyprland-protocols",
"hyprland-protocols": "hyprland-protocols_2",
"hyprlang": [
"hyprlang"
],
"hyprutils": [
"hyprutils"
],
"hyprwayland-scanner": [
"hyprwayland-scanner"
],
"nixpkgs": [
"nixpkgs"
],
@@ -152,11 +239,11 @@
]
},
"locked": {
"lastModified": 1716290197,
"narHash": "sha256-1u9Exrc7yx9qtES2brDh7/DDZ8w8ap1nboIOAtCgeuM=",
"lastModified": 1727524473,
"narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "91e48d6acd8a5a611d26f925e51559ab743bc438",
"rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26",
"type": "github"
},
"original": {

View File

@@ -7,6 +7,14 @@
# <https://github.com/nix-systems/nix-systems>
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 = {
url = "github:hyprwm/hyprcursor";
inputs.nixpkgs.follows = "nixpkgs";
@@ -14,10 +22,23 @@
inputs.hyprlang.follows = "hyprlang";
};
hyprland-protocols = {
url = "github:hyprwm/hyprland-protocols";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
hyprlang = {
url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprutils.follows = "hyprutils";
};
hyprutils = {
url = "github:hyprwm/hyprutils";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
hyprwayland-scanner = {
@@ -31,6 +52,8 @@
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprlang.follows = "hyprlang";
inputs.hyprutils.follows = "hyprutils";
inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
};
};
@@ -50,6 +73,15 @@
hyprland-extras
];
});
pkgsCrossFor = eachSystem (system: crossSystem:
import nixpkgs {
localSystem = system;
crossSystem = crossSystem;
overlays = with self.overlays; [
hyprland-packages
hyprland-extras
];
});
in {
overlays = import ./nix/overlays.nix {inherit self lib inputs;};
@@ -75,17 +107,18 @@
xdg-desktop-portal-hyprland
;
hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
});
devShells = eachSystem (system: {
default =
pkgsFor.${system}.mkShell.override {
stdenv = pkgsFor.${system}.gcc13Stdenv;
inherit (self.packages.${system}.default) stdenv;
} {
name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [expat libxml2];
hardeningDisable = ["fortify"];
inputsFrom = [pkgsFor.${system}.hyprland];
packages = [pkgsFor.${system}.clang-tools];
};
});

View File

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

View File

@@ -1,4 +0,0 @@
all:
$(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl
clean:
rm ./hyprctl

View File

@@ -38,7 +38,8 @@ commands:
plugin ... Issue a plugin request
reload [config-only] Issue a reload to force reload the config. Pass
'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
manager
seterror <color> <message...> Sets the hyprctl error string. Color has

View File

@@ -1,17 +1,17 @@
_hyprctl_cmd_2 () {
hyprctl monitors | grep Monitor | awk '{ print $2 }'
_hyprctl_cmd_1 () {
hyprctl monitors | awk '/Monitor/{ print $2 }'
}
_hyprctl_cmd_3 () {
hyprpm list | grep "Plugin" | awk '{print $4}'
hyprctl clients | awk '/class/{print $2}'
}
_hyprctl_cmd_2 () {
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
}
_hyprctl_cmd_0 () {
hyprctl clients | grep class | awk '{print $2}'
}
_hyprctl_cmd_1 () {
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
hyprpm list | awk '/Plugin/{print $4}'
}
_hyprctl () {
@@ -23,25 +23,25 @@ _hyprctl () {
local words cword
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
declare -a literals=(resizeactive 2 changegroupactive -r moveintogroup forceallowsinput 4 ::= systeminfo all layouts setprop animationstyle switchxkblayout create denywindowfromgroup headless activebordercolor exec setcursor wayland focusurgentorlast workspacerules movecurrentworkspacetomonitor movetoworkspacesilent hyprpaper alpha inactivebordercolor movegroupwindow movecursortocorner movewindowpixel prev movewindow globalshortcuts clients dimaround setignoregrouplock splash execr monitors 0 forcenoborder -q animations 1 nomaxsize splitratio moveactive pass swapnext devices layers rounding lockactivegroup 5 moveworkspacetomonitor -f -i --quiet forcenodim pin 0 1 forceopaque forcenoshadow setfloating minsize alphaoverride sendshortcut workspaces cyclenext alterzorder togglegroup lockgroups bordersize dpms focuscurrentorlast -1 --batch notify remove instances 1 3 moveoutofgroup killactive 2 movetoworkspace movecursor configerrors closewindow swapwindow tagwindow forcerendererreload centerwindow auto focuswindow seterror nofocus alphafullscreen binds version -h togglespecialworkspace fullscreen windowdancecompat 0 keyword toggleopaque 3 --instance togglefloating renameworkspace alphafullscreenoverride activeworkspace x11 kill forceopaqueoverriden output global dispatch reload forcenoblur -j event --help disable -1 activewindow keepaspectratio dismissnotify focusmonitor movefocus plugin exit workspace fullscreenstate getoption alphainactiveoverride alphainactive decorations settiled config-only descriptions resizewindowpixel fakefullscreen rollinglog swapactiveworkspaces submap next movewindoworgroup cursorpos forcenoanims focusworkspaceoncurrentmonitor maxsize)
declare -A literal_transitions
literal_transitions[0]="([105]=1 [75]=2 [33]=3 [35]=4 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [111]=4 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [88]=4 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [98]=4 [99]=2 [27]=2 [28]=14 [102]=2 [104]=4)"
literal_transitions[3]="([73]=17 [13]=2 [32]=17 [55]=17 [56]=17 [91]=17 [106]=2 [123]=2 [77]=1 [16]=2 [126]=17 [3]=1 [5]=2 [64]=17 [131]=2 [133]=17 [81]=17 [134]=17 [84]=17 [31]=17 [49]=2 [12]=2 [86]=17 [10]=17 [87]=17 [141]=17)"
literal_transitions[7]="([105]=1 [75]=2 [33]=3 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [99]=2 [27]=2 [28]=14 [102]=2)"
literal_transitions[8]="([101]=2 [130]=2 [132]=2 [0]=2 [74]=2 [36]=2 [108]=2 [109]=2 [38]=2 [110]=2 [4]=2 [79]=2 [40]=2 [80]=2 [113]=2 [6]=2 [42]=2 [43]=2 [82]=2 [83]=2 [47]=2 [48]=2 [9]=2 [50]=2 [51]=2 [53]=2 [11]=2 [112]=2 [89]=2 [118]=2 [57]=2 [92]=2 [58]=2 [93]=2 [94]=2 [61]=2 [62]=2 [128]=2 [95]=2 [63]=2 [20]=2 [97]=2 [22]=2 [23]=2 [65]=2 [66]=2 [135]=2 [136]=2 [24]=2 [26]=2 [69]=2 [100]=2 [70]=2 [140]=2 [29]=2 [71]=2)"
literal_transitions[9]="([117]=20 [114]=16)"
literal_transitions[11]="([103]=2)"
literal_transitions[13]="([21]=1 [119]=1 [30]=1 [139]=1 [121]=1 [44]=1 [72]=1)"
literal_transitions[14]="([39]=2)"
literal_transitions[15]="([138]=2 [96]=2)"
literal_transitions[17]="([18]=2 [7]=2)"
literal_transitions[18]="([76]=19)"
literal_transitions[19]="([34]=4 [45]=4)"
literal_transitions[20]="([8]=2 [67]=2 [14]=2 [137]=2)"
declare -A match_anything_transitions
match_anything_transitions=([1]=2 [0]=7 [6]=2 [15]=2 [10]=2 [5]=15 [14]=18 [7]=7 [2]=18 [16]=2 [12]=2 [11]=18)
literal_transitions[0]="([120]=14 [43]=2 [125]=21 [81]=2 [3]=21 [51]=2 [50]=2 [128]=2 [89]=2 [58]=21 [8]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [102]=21 [133]=7 [100]=2 [137]=2 [22]=2 [19]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [78]=21 [114]=2 [37]=2 [151]=2 [116]=2 [121]=13 [123]=21 [39]=11 [42]=21 [79]=15 [118]=12)"
literal_transitions[1]="([81]=2 [51]=2 [50]=2 [128]=2 [8]=2 [89]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [133]=7 [100]=2 [22]=2 [19]=2 [137]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [114]=2 [37]=2 [151]=2 [116]=2 [39]=11 [118]=12 [121]=13 [120]=14 [79]=15 [43]=2)"
literal_transitions[3]="([139]=2 [63]=16 [64]=16 [45]=16 [105]=16 [27]=2 [26]=2 [52]=4 [5]=16 [66]=2 [67]=16 [129]=16 [113]=16 [12]=2 [74]=4 [99]=2 [35]=16 [152]=16 [98]=16 [59]=16 [117]=16 [41]=16 [17]=2 [138]=16 [154]=2 [122]=16)"
literal_transitions[6]="([126]=2)"
literal_transitions[10]="([56]=2)"
literal_transitions[11]="([9]=2)"
literal_transitions[12]="([14]=19 [80]=22)"
literal_transitions[13]="([142]=2)"
literal_transitions[14]="([0]=2 [84]=2 [2]=2 [85]=2 [4]=2 [87]=2 [88]=2 [90]=2 [91]=2 [92]=2 [93]=2 [94]=2 [96]=2 [15]=2 [18]=2 [103]=2 [21]=2 [104]=2 [23]=2 [24]=2 [28]=2 [29]=2 [30]=2 [108]=2 [111]=2 [32]=2 [112]=2 [36]=2 [38]=2 [119]=2 [124]=2 [46]=2 [47]=2 [48]=2 [49]=2 [53]=2 [55]=2 [131]=2 [132]=2 [134]=2 [135]=2 [60]=2 [136]=20 [141]=2 [65]=2 [144]=2 [145]=2 [68]=2 [147]=2 [70]=2 [71]=2 [72]=2 [73]=2 [148]=2 [75]=2 [76]=2 [150]=2 [153]=2)"
literal_transitions[15]="([86]=4 [6]=4 [109]=4 [61]=4 [77]=4 [54]=4 [62]=4)"
literal_transitions[16]="([40]=2 [44]=2)"
literal_transitions[17]="([7]=23)"
literal_transitions[18]="([31]=2 [149]=2)"
literal_transitions[19]="([95]=2 [16]=2 [115]=2 [20]=2)"
literal_transitions[20]="([106]=2 [82]=2 [127]=2 [1]=2 [83]=2)"
literal_transitions[23]="([57]=21 [110]=21)"
declare -A match_anything_transitions=([6]=17 [7]=2 [0]=1 [22]=2 [5]=18 [4]=2 [2]=17 [18]=2 [11]=17 [8]=2 [9]=2 [13]=17 [10]=17 [1]=1)
declare -A subword_transitions
local state=0
@@ -79,21 +79,9 @@ _hyprctl () {
done
local -a matches=()
local prefix="${words[$cword]}"
local shortest_suffix="$word"
for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
local char="${COMP_WORDBREAKS:$i:1}"
local candidate="${word##*$char}"
if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
shortest_suffix=$candidate
fi
done
local superfluous_prefix=""
if [[ "$shortest_suffix" != "$word" ]]; then
local superfluous_prefix=${word%$shortest_suffix}
fi
if [[ -v "literal_transitions[$state]" ]]; then
local state_transitions_initializer=${literal_transitions[$state]}
declare -A state_transitions
@@ -102,25 +90,38 @@ _hyprctl () {
for literal_id in "${!state_transitions[@]}"; do
local literal="${literals[$literal_id]}"
if [[ $literal = "${prefix}"* ]]; then
local completion=${literal#"$superfluous_prefix"}
COMPREPLY+=("$completion ")
matches+=("$literal ")
fi
done
fi
declare -A commands
commands=([5]=1 [16]=2 [12]=3 [10]=0)
commands=([7]=0 [22]=1 [8]=3 [5]=2)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
local completions=()
mapfile -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1)
readarray -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1)
for item in "${completions[@]}"; do
if [[ $item = "${prefix}"* ]]; then
COMPREPLY+=("$item")
matches+=("$item")
fi
done
fi
local shortest_suffix="$prefix"
for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
local char="${COMP_WORDBREAKS:$i:1}"
local candidate=${prefix##*$char}
if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
shortest_suffix=$candidate
fi
done
local superfluous_prefix=""
if [[ "$shortest_suffix" != "$prefix" ]]; then
local superfluous_prefix=${prefix%$shortest_suffix}
fi
COMPREPLY=("${matches[@]#$superfluous_prefix}")
return 0
}

View File

@@ -1,21 +1,21 @@
function _hyprctl_3
function _hyprctl_2
set 1 $argv[1]
hyprctl monitors | grep Monitor | awk '{ print $2 }'
hyprctl monitors | awk '/Monitor/{ print $2 }'
end
function _hyprctl_4
set 1 $argv[1]
hyprpm list | grep "Plugin" | awk '{print $4}'
hyprctl clients | awk '/class/{print $2}'
end
function _hyprctl_3
set 1 $argv[1]
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
end
function _hyprctl_1
set 1 $argv[1]
hyprctl clients | grep class | awk '{print $2}'
end
function _hyprctl_2
set 1 $argv[1]
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
hyprpm list | awk '/Plugin/{print $4}'
end
function _hyprctl
@@ -29,145 +29,160 @@ function _hyprctl
set COMP_CWORD (count $COMP_WORDS)
end
set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow"
set literals "resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize"
set --local descriptions
set descriptions[1] "Focus the next window on a workspace"
set descriptions[3] "Get the current cursor pos in global layout coordinates"
set descriptions[5] "Rename a workspace"
set descriptions[7] "Focus the first window matching"
set descriptions[10] "Swap the focused window with the next window"
set descriptions[12] "Move the active window"
set descriptions[16] "List the layers"
set descriptions[18] "List active outputs with their properties"
set descriptions[20] "Get into a kill mode, where you can kill an app by clicking on it"
set descriptions[21] "Set the current window's floating state to false"
set descriptions[22] "ERROR"
set descriptions[23] "Focus a monitor"
set descriptions[24] "Swap the active window with another window"
set descriptions[25] "Move the active window out of a group"
set descriptions[26] "Send a notification using the built-in Hyprland notification system"
set descriptions[27] "Move the cursor to a specified position"
set descriptions[28] "Set the cursor theme and reloads the cursor manager"
set descriptions[29] "Set the hyprctl error string"
set descriptions[30] "Move the active workspace to a monitor"
set descriptions[31] "CONFUSED"
set descriptions[34] "Set a property of a window"
set descriptions[35] "Specify the Hyprland instance"
set descriptions[36] "Disable output"
set descriptions[37] "Toggle the current window's floating state"
set descriptions[38] "Get the list of defined workspace rules"
set descriptions[39] "Move the focused window to a workspace"
set descriptions[41] "Temporarily enable or disable binds:ignore_group_lock"
set descriptions[42] "List all workspaces with their properties"
set descriptions[43] "Swap the active window with the next or previous in a group"
set descriptions[44] "Close a specified window"
set descriptions[45] "WARNING"
set descriptions[46] "Specify the Hyprland instance"
set descriptions[47] "List all registered binds"
set descriptions[48] "Move the active window in a direction or to a monitor"
set descriptions[49] "Change the split ratio"
set descriptions[51] "Prohibit the active window from becoming or being inserted into group"
set descriptions[52] "Change the workspace"
set descriptions[53] "List all current config parsing errors"
set descriptions[54] "Toggle the current active window into a group"
set descriptions[55] "Get the config option status (values)"
set descriptions[58] "Close the active window"
set descriptions[59] "Pass the key to a specified window"
set descriptions[60] "List all decorations and their info"
set descriptions[61] "List all connected keyboards and mice"
set descriptions[62] "Switch focus from current to previously focused window"
set descriptions[63] "Change the current mapping group"
set descriptions[64] "Execute a Global Shortcut using the GlobalShortcuts portal"
set descriptions[66] "Force the renderer to reload all resources and outputs"
set descriptions[67] "Move a selected window"
set descriptions[69] "Print the Hyprland version: flags, commit and branch of build"
set descriptions[70] "Set all monitors' DPMS status"
set descriptions[71] "Resize the active window"
set descriptions[72] "Move the active window into a group"
set descriptions[73] "OK"
set descriptions[75] "Set the current window's floating state to true"
set descriptions[76] "Print tail of the log"
set descriptions[79] "List all layouts available (including plugin ones)"
set descriptions[80] "Move a workspace to a monitor"
set descriptions[81] "Execute a shell command"
set descriptions[83] "Modify the window stack order of the active or specified window"
set descriptions[84] "Toggle the focused window's internal fullscreen state"
set descriptions[86] "Issue a keyword to call a config keyword dynamically"
set descriptions[89] "Disable output"
set descriptions[90] "Pin a window"
set descriptions[91] "Allows adding/removing fake outputs to a specific backend"
set descriptions[93] "Toggle a special workspace on/off"
set descriptions[94] "Toggle the focused window's fullscreen state"
set descriptions[95] "Toggle the current window to always be opaque"
set descriptions[96] "Focus the requested workspace"
set descriptions[98] "Switch to the next window in a group"
set descriptions[99] "Output in JSON format"
set descriptions[100] "List all running Hyprland instances and their info"
set descriptions[101] "Execute a raw shell command"
set descriptions[102] "Exit the compositor with no questions asked"
set descriptions[103] "List all windows with their properties"
set descriptions[105] "Execute a batch of commands separated by ;"
set descriptions[106] "Dismiss all or up to amount of notifications"
set descriptions[108] "Set the xkb layout index for a keyboard"
set descriptions[109] "Move window doesnt switch to the workspace"
set descriptions[110] "Apply a tag to the window"
set descriptions[111] "Behave as moveintogroup"
set descriptions[112] "Refresh state after issuing the command"
set descriptions[113] "Move the focus in a direction"
set descriptions[114] "Focus the urgent window or the last window"
set descriptions[116] "Get the active workspace name and its properties"
set descriptions[117] "Issue a dispatch to call a keybind dispatcher with an arg"
set descriptions[119] "Center the active window"
set descriptions[120] "HINT"
set descriptions[121] "Interact with hyprpaper if present"
set descriptions[122] "No Icon"
set descriptions[123] "Force reload the config"
set descriptions[125] "Print system info"
set descriptions[126] "Interact with a plugin"
set descriptions[128] "Get the active window name and its properties"
set descriptions[129] "Swap the active workspaces between two monitors"
set descriptions[130] "Print the current random splash"
set descriptions[131] "On shortcut X sends shortcut Y to a specified window"
set descriptions[133] "Lock the focused group"
set descriptions[136] "Lock the groups"
set descriptions[137] "Move the cursor to the corner of the active window"
set descriptions[140] "INFO"
set descriptions[141] "Resize a selected window"
set descriptions
set descriptions[1] "Resize the active window"
set descriptions[2] "Fullscreen"
set descriptions[3] "Switch to the next window in a group"
set descriptions[4] "Refresh state after issuing the command"
set descriptions[5] "Move the active window into a group"
set descriptions[7] "CONFUSED"
set descriptions[9] "Print system info"
set descriptions[11] "List all layouts available (including plugin ones)"
set descriptions[12] "Set a property of a window"
set descriptions[14] "Set the xkb layout index for a keyboard"
set descriptions[16] "Prohibit the active window from becoming or being inserted into group"
set descriptions[19] "Execute a shell command"
set descriptions[20] "Set the cursor theme and reloads the cursor manager"
set descriptions[22] "Focus the urgent window or the last window"
set descriptions[23] "Get the list of defined workspace rules"
set descriptions[24] "Move the active workspace to a monitor"
set descriptions[25] "Move window doesnt switch to the workspace"
set descriptions[26] "Interact with hyprpaper if present"
set descriptions[29] "Swap the active window with the next or previous in a group"
set descriptions[30] "Move the cursor to the corner of the active window"
set descriptions[31] "Move a selected window"
set descriptions[33] "Move the active window in a direction or to a monitor"
set descriptions[34] "Lists all global shortcuts"
set descriptions[35] "List all windows with their properties"
set descriptions[37] "Temporarily enable or disable binds:ignore_group_lock"
set descriptions[38] "Print the current random splash"
set descriptions[39] "Execute a raw shell command"
set descriptions[40] "List active outputs with their properties"
set descriptions[43] "Disable output"
set descriptions[44] "Gets the current config info about animations and beziers"
set descriptions[47] "Change the split ratio"
set descriptions[48] "Move the active window"
set descriptions[49] "Pass the key to a specified window"
set descriptions[50] "Swap the focused window with the next window"
set descriptions[51] "List all connected keyboards and mice"
set descriptions[52] "List the layers"
set descriptions[54] "Lock the focused group"
set descriptions[55] "OK"
set descriptions[56] "Move a workspace to a monitor"
set descriptions[58] "Specify the Hyprland instance"
set descriptions[59] "Disable output"
set descriptions[61] "Pin a window"
set descriptions[62] "WARNING"
set descriptions[63] "INFO"
set descriptions[66] "Set the current window's floating state to true"
set descriptions[69] "On shortcut X sends shortcut Y to a specified window"
set descriptions[70] "List all workspaces with their properties"
set descriptions[71] "Focus the next window on a workspace"
set descriptions[72] "Modify the window stack order of the active or specified window"
set descriptions[73] "Toggle the current active window into a group"
set descriptions[74] "Lock the groups"
set descriptions[76] "Set all monitors' DPMS status"
set descriptions[77] "Switch focus from current to previously focused window"
set descriptions[78] "No Icon"
set descriptions[79] "Execute a batch of commands separated by ;"
set descriptions[80] "Send a notification using the built-in Hyprland notification system"
set descriptions[82] "List all running Hyprland instances and their info"
set descriptions[83] "Maximize no fullscreen"
set descriptions[84] "Maximize and fullscreen"
set descriptions[85] "Move the active window out of a group"
set descriptions[86] "Close the active window"
set descriptions[87] "HINT"
set descriptions[88] "Move the focused window to a workspace"
set descriptions[89] "Move the cursor to a specified position"
set descriptions[90] "List all current config parsing errors"
set descriptions[91] "Close a specified window"
set descriptions[92] "Swap the active window with another window"
set descriptions[93] "Apply a tag to the window"
set descriptions[94] "Force the renderer to reload all resources and outputs"
set descriptions[95] "Center the active window"
set descriptions[97] "Focus the first window matching"
set descriptions[98] "Set the hyprctl error string"
set descriptions[101] "List all registered binds"
set descriptions[102] "Print the Hyprland version: flags, commit and branch of build"
set descriptions[103] "Prints the help message"
set descriptions[104] "Toggle a special workspace on/off"
set descriptions[105] "Toggle the focused window's fullscreen state"
set descriptions[107] "None"
set descriptions[108] "Issue a keyword to call a config keyword dynamically"
set descriptions[109] "Toggle the current window to always be opaque"
set descriptions[110] "ERROR"
set descriptions[111] "Specify the Hyprland instance"
set descriptions[112] "Toggle the current window's floating state"
set descriptions[113] "Rename a workspace"
set descriptions[115] "Get the active workspace name and its properties"
set descriptions[117] "Get into a kill mode, where you can kill an app by clicking on it"
set descriptions[119] "Allows adding/removing fake outputs to a specific backend"
set descriptions[120] "Execute a Global Shortcut using the GlobalShortcuts portal"
set descriptions[121] "Issue a dispatch to call a keybind dispatcher with an arg"
set descriptions[122] "Force reload the config"
set descriptions[124] "Output in JSON format"
set descriptions[125] "Emits a custom event to socket2"
set descriptions[126] "Prints the help message"
set descriptions[128] "Current"
set descriptions[129] "Get the active window name and its properties"
set descriptions[131] "Dismiss all or up to amount of notifications"
set descriptions[132] "Focus a monitor"
set descriptions[133] "Move the focus in a direction"
set descriptions[134] "Interact with a plugin"
set descriptions[135] "Exit the compositor with no questions asked"
set descriptions[136] "Change the workspace"
set descriptions[137] "Sets the focused windows fullscreen mode and the one sent to the client"
set descriptions[138] "Get the config option status (values)"
set descriptions[141] "List all decorations and their info"
set descriptions[142] "Set the current window's floating state to false"
set descriptions[144] "Return a parsable JSON with all the config options, descriptions, value types and ranges"
set descriptions[145] "Resize a selected window"
set descriptions[146] "Toggle the focused window's internal fullscreen state"
set descriptions[147] "Print tail of the log"
set descriptions[148] "Swap the active workspaces between two monitors"
set descriptions[149] "Change the current mapping group"
set descriptions[151] "Behave as moveintogroup"
set descriptions[152] "Get the current cursor pos in global layout coordinates"
set descriptions[154] "Focus the requested workspace"
set --local literal_transitions
set literal_transitions[1] "set inputs 106 76 34 36 2 3 79 108 38 112 42 47 116 86 117 53 89 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 99 100 28 29 103 105; set tos 2 3 4 5 3 3 3 6 3 5 3 3 3 7 9 3 5 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 5 3 3 15 3 5"
set literal_transitions[4] "set inputs 74 14 33 56 57 92 107 124 78 17 127 4 6 65 132 134 82 135 85 32 50 13 87 11 88 142; set tos 18 3 18 18 18 18 3 3 2 3 18 2 3 18 3 18 18 18 18 18 3 3 18 18 18 18"
set literal_transitions[8] "set inputs 106 76 34 2 3 79 108 38 42 47 116 86 117 53 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 100 28 29 103; set tos 2 3 4 3 3 3 6 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3"
set literal_transitions[9] "set inputs 102 131 133 1 75 37 109 110 39 111 5 80 41 81 114 7 43 44 83 84 48 49 10 51 52 54 12 113 90 119 58 93 59 94 95 62 63 129 96 64 21 98 23 24 66 67 136 137 25 27 70 101 71 141 30 72; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3"
set literal_transitions[10] "set inputs 118 115; set tos 21 17"
set literal_transitions[12] "set inputs 104; set tos 3"
set literal_transitions[14] "set inputs 22 120 31 140 122 45 73; set tos 2 2 2 2 2 2 2"
set literal_transitions[15] "set inputs 40; set tos 3"
set literal_transitions[16] "set inputs 139 97; set tos 3 3"
set literal_transitions[18] "set inputs 19 8; set tos 3 3"
set literal_transitions[19] "set inputs 77; set tos 20"
set literal_transitions[20] "set inputs 35 46; set tos 5 5"
set literal_transitions[21] "set inputs 9 68 15 138; set tos 3 3 3 3"
set literal_transitions
set literal_transitions[1] "set inputs 121 44 126 82 4 52 51 129 90 59 9 11 12 131 14 98 102 103 134 101 138 23 20 141 26 144 108 147 70 34 35 79 115 38 152 117 122 124 40 43 80 119; set tos 15 3 22 3 22 3 3 3 3 22 3 3 4 5 6 7 3 22 8 3 3 3 3 9 3 3 10 11 3 3 3 22 3 3 3 3 14 22 12 22 16 13"
set literal_transitions[2] "set inputs 82 52 51 129 9 90 11 12 131 14 98 102 134 101 23 20 138 141 26 144 108 147 70 34 35 115 38 152 117 40 119 122 121 80 44; set tos 3 3 3 3 3 3 3 4 5 6 7 3 8 3 3 3 3 9 3 3 10 11 3 3 3 3 3 3 3 12 13 14 15 16 3"
set literal_transitions[4] "set inputs 140 64 65 46 106 28 27 53 6 67 68 130 114 13 75 100 36 153 99 60 118 42 18 139 155 123; set tos 3 17 17 17 17 3 3 5 17 3 17 17 17 3 5 3 17 17 17 17 17 17 3 17 3 17"
set literal_transitions[7] "set inputs 127; set tos 3"
set literal_transitions[11] "set inputs 57; set tos 3"
set literal_transitions[12] "set inputs 10; set tos 3"
set literal_transitions[13] "set inputs 15 81; set tos 20 23"
set literal_transitions[14] "set inputs 143; set tos 3"
set literal_transitions[15] "set inputs 1 85 3 86 5 88 89 91 92 93 94 95 97 16 19 104 22 105 24 25 29 30 31 109 112 33 113 37 39 120 125 47 48 49 50 54 56 132 133 135 136 61 137 142 66 145 146 69 148 71 72 73 74 149 76 77 151 154; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 21 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3"
set literal_transitions[16] "set inputs 87 7 110 62 78 55 63; set tos 5 5 5 5 5 5 5"
set literal_transitions[17] "set inputs 41 45; set tos 3 3"
set literal_transitions[18] "set inputs 8; set tos 24"
set literal_transitions[19] "set inputs 32 150; set tos 3 3"
set literal_transitions[20] "set inputs 96 17 116 21; set tos 3 3 3 3"
set literal_transitions[21] "set inputs 107 83 128 2 84; set tos 3 3 3 3 3"
set literal_transitions[24] "set inputs 58 111; set tos 22 22"
set --local match_anything_transitions_from 2 1 7 16 11 6 15 8 3 17 13 12
set --local match_anything_transitions_to 3 8 3 3 3 16 19 8 19 3 3 19
set match_anything_transitions_from 7 8 1 23 6 5 3 19 12 9 10 14 11 2
set match_anything_transitions_to 18 3 2 3 19 3 18 3 18 3 3 18 18 2
set --local state 1
set --local word_index 2
set state 1
set word_index 2
while test $word_index -lt $COMP_CWORD
set --local -- word $COMP_WORDS[$word_index]
set -- word $COMP_WORDS[$word_index]
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
set --local --erase inputs
set --local --erase tos
set --erase inputs
set --erase tos
eval $literal_transitions[$state]
if contains -- $word $literals
set --local literal_matched 0
set literal_matched 0
for literal_id in (seq 1 (count $literals))
if test $literals[$literal_id] = $word
set --local index (contains --index -- $literal_id $inputs)
set index (contains --index -- $literal_id $inputs)
set state $tos[$index]
set word_index (math $word_index + 1)
set literal_matched 1
@@ -181,7 +196,7 @@ function _hyprctl
end
if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state]
set --local index (contains --index -- $state $match_anything_transitions_from)
set index (contains --index -- $state $match_anything_transitions_from)
set state $match_anything_transitions_to[$index]
set word_index (math $word_index + 1)
continue
@@ -191,8 +206,8 @@ function _hyprctl
end
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
set --local --erase inputs
set --local --erase tos
set --erase inputs
set --erase tos
eval $literal_transitions[$state]
for literal_id in $inputs
if test -n $descriptions[$literal_id]
@@ -203,14 +218,14 @@ function _hyprctl
end
end
set command_states 6 17 13 11
set command_ids 2 3 4 1
set command_states 8 23 9 6
set command_ids 1 2 4 3
if contains $state $command_states
set --local index (contains --index $state $command_states)
set --local function_id $command_ids[$index]
set --local function_name _hyprctl_$function_id
set --local --erase inputs
set --local --erase tos
set index (contains --index $state $command_states)
set function_id $command_ids[$index]
set function_name _hyprctl_$function_id
set --erase inputs
set --erase tos
$function_name "$COMP_WORDS[$COMP_CWORD]"
end

View File

@@ -9,13 +9,14 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (-r) "Refresh state after issuing the command"
| (--batch) "Execute a batch of commands separated by ;"
| (-q | --quiet) "Disable output"
| (-h | --help) "Prints the help message"
;
<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}' }}};
@@ -59,16 +60,18 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
<ARGUMENTS> ::= (activewindow) "Get the active window name and its properties"
| (activeworkspace) "Get the active workspace name and its properties"
| (animations) "Gets the current config info about animations and beziers"
| (binds) "List all registered binds"
| (clients) "List all windows with their properties"
| (configerrors) "List all current config parsing errors"
| (cursorpos) "Get the current cursor pos in global layout coordinates"
| (decorations <WINDOWS>) "List all decorations and their info"
| (descriptions) "Return a parsable JSON with all the config options, descriptions, value types and ranges"
| (devices) "List all connected keyboards and mice"
| (dismissnotify <NUM>) "Dismiss all or up to amount of notifications"
| (dispatch <DISPATCHERS>) "Issue a dispatch to call a keybind dispatcher with an arg"
| (getoption) "Get the config option status (values)"
| (globalshortcuts) ""
| (globalshortcuts) "Lists all global shortcuts"
| (hyprpaper) "Interact with hyprpaper if present"
| (instances) "List all running Hyprland instances and their info"
| (keyword <KEYWORDS>) "Issue a keyword to call a config keyword dynamically"
@@ -79,8 +82,8 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (notify <NOTIFICATION_TYPES> <NUM>) "Send a notification using the built-in Hyprland notification system"
| (output (create (wayland | x11 | headless | auto) | remove <MONITORS>)) "Allows adding/removing fake outputs to a specific backend"
| (plugin <AVAILABLE_PLUGINS>) "Interact with a plugin"
| (reload) "Force reload the config"
| (rollinglog) "Print tail of the log"
| (reload [config-only]) "Force reload the config"
| (rollinglog [-f]) "Print tail of the log"
| (setcursor) "Set the cursor theme and reloads the cursor manager"
| (seterror [disable]) "Set the hyprctl error string"
| (setprop <PROPS>) "Set a property of a window"
@@ -92,6 +95,13 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (workspaces) "List all workspaces with their properties"
;
<WINDOW_STATE> ::= (-1) "Current"
| (0) "None"
| (1) "Maximize no fullscreen"
| (2) "Fullscreen"
| (3) "Maximize and fullscreen"
;
<DISPATCHERS> ::= (exec) "Execute a shell command"
| (execr) "Execute a raw shell command"
| (pass) "Pass the key to a specified window"
@@ -106,6 +116,7 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (settiled) "Set the current window's floating state to false"
| (fullscreen) "Toggle the focused window's fullscreen state"
| (fakefullscreen) "Toggle the focused window's internal fullscreen state"
| (fullscreenstate <WINDOW_STATE>) "Sets the focused windows fullscreen mode and the one sent to the client"
| (dpms) "Set all monitors' DPMS status"
| (pin) "Pin a window"
| (movefocus) "Move the focus in a direction"
@@ -148,4 +159,5 @@ hyprctl [<OPTIONS>]... <ARGUMENTS>
| (setignoregrouplock) "Temporarily enable or disable binds:ignore_group_lock"
| (global) "Execute a Global Shortcut using the GlobalShortcuts portal"
| (submap) "Change the current mapping group"
| (event) "Emits a custom event to socket2"
;

View File

@@ -1,143 +1,160 @@
_hyprctl_cmd_2 () {
hyprctl monitors | grep Monitor | awk '{ print $2 }'
#compdef hyprctl
_hyprctl_cmd_1 () {
hyprctl monitors | awk '/Monitor/{ print $2 }'
}
_hyprctl_cmd_3 () {
hyprpm list | grep "Plugin" | awk '{print $4}'
hyprctl clients | awk '/class/{print $2}'
}
_hyprctl_cmd_0 () {
hyprctl clients | grep class | awk '{print $2}'
}
_hyprctl_cmd_1 () {
_hyprctl_cmd_2 () {
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
}
_hyprctl_cmd_0 () {
hyprpm list | awk '/Plugin/{print $4}'
}
_hyprctl () {
local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
local -a literals=("resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize")
local -A descriptions
descriptions[1]="Focus the next window on a workspace"
descriptions[3]="Get the current cursor pos in global layout coordinates"
descriptions[5]="Rename a workspace"
descriptions[7]="Focus the first window matching"
descriptions[10]="Swap the focused window with the next window"
descriptions[12]="Move the active window"
descriptions[16]="List the layers"
descriptions[18]="List active outputs with their properties"
descriptions[20]="Get into a kill mode, where you can kill an app by clicking on it"
descriptions[21]="Set the current window's floating state to false"
descriptions[22]="ERROR"
descriptions[23]="Focus a monitor"
descriptions[24]="Swap the active window with another window"
descriptions[25]="Move the active window out of a group"
descriptions[26]="Send a notification using the built-in Hyprland notification system"
descriptions[27]="Move the cursor to a specified position"
descriptions[28]="Set the cursor theme and reloads the cursor manager"
descriptions[29]="Set the hyprctl error string"
descriptions[30]="Move the active workspace to a monitor"
descriptions[31]="CONFUSED"
descriptions[34]="Set a property of a window"
descriptions[35]="Specify the Hyprland instance"
descriptions[36]="Disable output"
descriptions[37]="Toggle the current window's floating state"
descriptions[38]="Get the list of defined workspace rules"
descriptions[39]="Move the focused window to a workspace"
descriptions[41]="Temporarily enable or disable binds:ignore_group_lock"
descriptions[42]="List all workspaces with their properties"
descriptions[43]="Swap the active window with the next or previous in a group"
descriptions[44]="Close a specified window"
descriptions[45]="WARNING"
descriptions[46]="Specify the Hyprland instance"
descriptions[47]="List all registered binds"
descriptions[48]="Move the active window in a direction or to a monitor"
descriptions[49]="Change the split ratio"
descriptions[51]="Prohibit the active window from becoming or being inserted into group"
descriptions[52]="Change the workspace"
descriptions[53]="List all current config parsing errors"
descriptions[54]="Toggle the current active window into a group"
descriptions[55]="Get the config option status (values)"
descriptions[58]="Close the active window"
descriptions[59]="Pass the key to a specified window"
descriptions[60]="List all decorations and their info"
descriptions[61]="List all connected keyboards and mice"
descriptions[62]="Switch focus from current to previously focused window"
descriptions[63]="Change the current mapping group"
descriptions[64]="Execute a Global Shortcut using the GlobalShortcuts portal"
descriptions[66]="Force the renderer to reload all resources and outputs"
descriptions[67]="Move a selected window"
descriptions[69]="Print the Hyprland version: flags, commit and branch of build"
descriptions[70]="Set all monitors' DPMS status"
descriptions[71]="Resize the active window"
descriptions[72]="Move the active window into a group"
descriptions[73]="OK"
descriptions[75]="Set the current window's floating state to true"
descriptions[76]="Print tail of the log"
descriptions[79]="List all layouts available (including plugin ones)"
descriptions[80]="Move a workspace to a monitor"
descriptions[81]="Execute a shell command"
descriptions[83]="Modify the window stack order of the active or specified window"
descriptions[84]="Toggle the focused window's internal fullscreen state"
descriptions[86]="Issue a keyword to call a config keyword dynamically"
descriptions[89]="Disable output"
descriptions[90]="Pin a window"
descriptions[91]="Allows adding/removing fake outputs to a specific backend"
descriptions[93]="Toggle a special workspace on/off"
descriptions[94]="Toggle the focused window's fullscreen state"
descriptions[95]="Toggle the current window to always be opaque"
descriptions[96]="Focus the requested workspace"
descriptions[98]="Switch to the next window in a group"
descriptions[99]="Output in JSON format"
descriptions[100]="List all running Hyprland instances and their info"
descriptions[101]="Execute a raw shell command"
descriptions[102]="Exit the compositor with no questions asked"
descriptions[103]="List all windows with their properties"
descriptions[105]="Execute a batch of commands separated by ;"
descriptions[106]="Dismiss all or up to amount of notifications"
descriptions[108]="Set the xkb layout index for a keyboard"
descriptions[109]="Move window doesnt switch to the workspace"
descriptions[110]="Apply a tag to the window"
descriptions[111]="Behave as moveintogroup"
descriptions[112]="Refresh state after issuing the command"
descriptions[113]="Move the focus in a direction"
descriptions[114]="Focus the urgent window or the last window"
descriptions[116]="Get the active workspace name and its properties"
descriptions[117]="Issue a dispatch to call a keybind dispatcher with an arg"
descriptions[119]="Center the active window"
descriptions[120]="HINT"
descriptions[121]="Interact with hyprpaper if present"
descriptions[122]="No Icon"
descriptions[123]="Force reload the config"
descriptions[125]="Print system info"
descriptions[126]="Interact with a plugin"
descriptions[128]="Get the active window name and its properties"
descriptions[129]="Swap the active workspaces between two monitors"
descriptions[130]="Print the current random splash"
descriptions[131]="On shortcut X sends shortcut Y to a specified window"
descriptions[133]="Lock the focused group"
descriptions[136]="Lock the groups"
descriptions[137]="Move the cursor to the corner of the active window"
descriptions[140]="INFO"
descriptions[141]="Resize a selected window"
descriptions[1]="Resize the active window"
descriptions[2]="Fullscreen"
descriptions[3]="Switch to the next window in a group"
descriptions[4]="Refresh state after issuing the command"
descriptions[5]="Move the active window into a group"
descriptions[7]="CONFUSED"
descriptions[9]="Print system info"
descriptions[11]="List all layouts available (including plugin ones)"
descriptions[12]="Set a property of a window"
descriptions[14]="Set the xkb layout index for a keyboard"
descriptions[16]="Prohibit the active window from becoming or being inserted into group"
descriptions[19]="Execute a shell command"
descriptions[20]="Set the cursor theme and reloads the cursor manager"
descriptions[22]="Focus the urgent window or the last window"
descriptions[23]="Get the list of defined workspace rules"
descriptions[24]="Move the active workspace to a monitor"
descriptions[25]="Move window doesnt switch to the workspace"
descriptions[26]="Interact with hyprpaper if present"
descriptions[29]="Swap the active window with the next or previous in a group"
descriptions[30]="Move the cursor to the corner of the active window"
descriptions[31]="Move a selected window"
descriptions[33]="Move the active window in a direction or to a monitor"
descriptions[34]="Lists all global shortcuts"
descriptions[35]="List all windows with their properties"
descriptions[37]="Temporarily enable or disable binds:ignore_group_lock"
descriptions[38]="Print the current random splash"
descriptions[39]="Execute a raw shell command"
descriptions[40]="List active outputs with their properties"
descriptions[43]="Disable output"
descriptions[44]="Gets the current config info about animations and beziers"
descriptions[47]="Change the split ratio"
descriptions[48]="Move the active window"
descriptions[49]="Pass the key to a specified window"
descriptions[50]="Swap the focused window with the next window"
descriptions[51]="List all connected keyboards and mice"
descriptions[52]="List the layers"
descriptions[54]="Lock the focused group"
descriptions[55]="OK"
descriptions[56]="Move a workspace to a monitor"
descriptions[58]="Specify the Hyprland instance"
descriptions[59]="Disable output"
descriptions[61]="Pin a window"
descriptions[62]="WARNING"
descriptions[63]="INFO"
descriptions[66]="Set the current window's floating state to true"
descriptions[69]="On shortcut X sends shortcut Y to a specified window"
descriptions[70]="List all workspaces with their properties"
descriptions[71]="Focus the next window on a workspace"
descriptions[72]="Modify the window stack order of the active or specified window"
descriptions[73]="Toggle the current active window into a group"
descriptions[74]="Lock the groups"
descriptions[76]="Set all monitors' DPMS status"
descriptions[77]="Switch focus from current to previously focused window"
descriptions[78]="No Icon"
descriptions[79]="Execute a batch of commands separated by ;"
descriptions[80]="Send a notification using the built-in Hyprland notification system"
descriptions[82]="List all running Hyprland instances and their info"
descriptions[83]="Maximize no fullscreen"
descriptions[84]="Maximize and fullscreen"
descriptions[85]="Move the active window out of a group"
descriptions[86]="Close the active window"
descriptions[87]="HINT"
descriptions[88]="Move the focused window to a workspace"
descriptions[89]="Move the cursor to a specified position"
descriptions[90]="List all current config parsing errors"
descriptions[91]="Close a specified window"
descriptions[92]="Swap the active window with another window"
descriptions[93]="Apply a tag to the window"
descriptions[94]="Force the renderer to reload all resources and outputs"
descriptions[95]="Center the active window"
descriptions[97]="Focus the first window matching"
descriptions[98]="Set the hyprctl error string"
descriptions[101]="List all registered binds"
descriptions[102]="Print the Hyprland version: flags, commit and branch of build"
descriptions[103]="Prints the help message"
descriptions[104]="Toggle a special workspace on/off"
descriptions[105]="Toggle the focused window's fullscreen state"
descriptions[107]="None"
descriptions[108]="Issue a keyword to call a config keyword dynamically"
descriptions[109]="Toggle the current window to always be opaque"
descriptions[110]="ERROR"
descriptions[111]="Specify the Hyprland instance"
descriptions[112]="Toggle the current window's floating state"
descriptions[113]="Rename a workspace"
descriptions[115]="Get the active workspace name and its properties"
descriptions[117]="Get into a kill mode, where you can kill an app by clicking on it"
descriptions[119]="Allows adding/removing fake outputs to a specific backend"
descriptions[120]="Execute a Global Shortcut using the GlobalShortcuts portal"
descriptions[121]="Issue a dispatch to call a keybind dispatcher with an arg"
descriptions[122]="Force reload the config"
descriptions[124]="Output in JSON format"
descriptions[125]="Emits a custom event to socket2"
descriptions[126]="Prints the help message"
descriptions[128]="Current"
descriptions[129]="Get the active window name and its properties"
descriptions[131]="Dismiss all or up to amount of notifications"
descriptions[132]="Focus a monitor"
descriptions[133]="Move the focus in a direction"
descriptions[134]="Interact with a plugin"
descriptions[135]="Exit the compositor with no questions asked"
descriptions[136]="Change the workspace"
descriptions[137]="Sets the focused windows fullscreen mode and the one sent to the client"
descriptions[138]="Get the config option status (values)"
descriptions[141]="List all decorations and their info"
descriptions[142]="Set the current window's floating state to false"
descriptions[144]="Return a parsable JSON with all the config options, descriptions, value types and ranges"
descriptions[145]="Resize a selected window"
descriptions[146]="Toggle the focused window's internal fullscreen state"
descriptions[147]="Print tail of the log"
descriptions[148]="Swap the active workspaces between two monitors"
descriptions[149]="Change the current mapping group"
descriptions[151]="Behave as moveintogroup"
descriptions[152]="Get the current cursor pos in global layout coordinates"
descriptions[154]="Focus the requested workspace"
local -A literal_transitions
literal_transitions[1]="([106]=2 [76]=3 [34]=4 [36]=5 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [112]=5 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [89]=5 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [99]=5 [100]=3 [28]=3 [29]=15 [103]=3 [105]=5)"
literal_transitions[4]="([74]=18 [14]=3 [33]=18 [56]=18 [57]=18 [92]=18 [107]=3 [124]=3 [78]=2 [17]=3 [127]=18 [4]=2 [6]=3 [65]=18 [132]=3 [134]=18 [82]=18 [135]=18 [85]=18 [32]=18 [50]=3 [13]=3 [87]=18 [11]=18 [88]=18 [142]=18)"
literal_transitions[8]="([106]=2 [76]=3 [34]=4 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [100]=3 [28]=3 [29]=15 [103]=3)"
literal_transitions[9]="([102]=3 [131]=3 [133]=3 [1]=3 [75]=3 [37]=3 [109]=3 [110]=3 [39]=3 [111]=3 [5]=3 [80]=3 [41]=3 [81]=3 [114]=3 [7]=3 [43]=3 [44]=3 [83]=3 [84]=3 [48]=3 [49]=3 [10]=3 [51]=3 [52]=3 [54]=3 [12]=3 [113]=3 [90]=3 [119]=3 [58]=3 [93]=3 [59]=3 [94]=3 [95]=3 [62]=3 [63]=3 [129]=3 [96]=3 [64]=3 [21]=3 [98]=3 [23]=3 [24]=3 [66]=3 [67]=3 [136]=3 [137]=3 [25]=3 [27]=3 [70]=3 [101]=3 [71]=3 [141]=3 [30]=3 [72]=3)"
literal_transitions[10]="([118]=21 [115]=17)"
literal_transitions[12]="([104]=3)"
literal_transitions[14]="([22]=2 [120]=2 [31]=2 [140]=2 [122]=2 [45]=2 [73]=2)"
literal_transitions[15]="([40]=3)"
literal_transitions[16]="([139]=3 [97]=3)"
literal_transitions[18]="([19]=3 [8]=3)"
literal_transitions[19]="([77]=20)"
literal_transitions[20]="([35]=5 [46]=5)"
literal_transitions[21]="([9]=3 [68]=3 [15]=3 [138]=3)"
literal_transitions[1]="([121]=15 [44]=3 [126]=22 [82]=3 [4]=22 [52]=3 [51]=3 [129]=3 [90]=3 [59]=22 [9]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [103]=22 [134]=8 [101]=3 [138]=3 [23]=3 [20]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [79]=22 [115]=3 [38]=3 [152]=3 [117]=3 [122]=14 [124]=22 [40]=12 [43]=22 [80]=16 [119]=13)"
literal_transitions[2]="([82]=3 [52]=3 [51]=3 [129]=3 [9]=3 [90]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [134]=8 [101]=3 [23]=3 [20]=3 [138]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [115]=3 [38]=3 [152]=3 [117]=3 [40]=12 [119]=13 [122]=14 [121]=15 [80]=16 [44]=3)"
literal_transitions[4]="([140]=3 [64]=17 [65]=17 [46]=17 [106]=17 [28]=3 [27]=3 [53]=5 [6]=17 [67]=3 [68]=17 [130]=17 [114]=17 [13]=3 [75]=5 [100]=3 [36]=17 [153]=17 [99]=17 [60]=17 [118]=17 [42]=17 [18]=3 [139]=17 [155]=3 [123]=17)"
literal_transitions[7]="([127]=3)"
literal_transitions[11]="([57]=3)"
literal_transitions[12]="([10]=3)"
literal_transitions[13]="([15]=20 [81]=23)"
literal_transitions[14]="([143]=3)"
literal_transitions[15]="([1]=3 [85]=3 [3]=3 [86]=3 [5]=3 [88]=3 [89]=3 [91]=3 [92]=3 [93]=3 [94]=3 [95]=3 [97]=3 [16]=3 [19]=3 [104]=3 [22]=3 [105]=3 [24]=3 [25]=3 [29]=3 [30]=3 [31]=3 [109]=3 [112]=3 [33]=3 [113]=3 [37]=3 [39]=3 [120]=3 [125]=3 [47]=3 [48]=3 [49]=3 [50]=3 [54]=3 [56]=3 [132]=3 [133]=3 [135]=3 [136]=3 [61]=3 [137]=21 [142]=3 [66]=3 [145]=3 [146]=3 [69]=3 [148]=3 [71]=3 [72]=3 [73]=3 [74]=3 [149]=3 [76]=3 [77]=3 [151]=3 [154]=3)"
literal_transitions[16]="([87]=5 [7]=5 [110]=5 [62]=5 [78]=5 [55]=5 [63]=5)"
literal_transitions[17]="([41]=3 [45]=3)"
literal_transitions[18]="([8]=24)"
literal_transitions[19]="([32]=3 [150]=3)"
literal_transitions[20]="([96]=3 [17]=3 [116]=3 [21]=3)"
literal_transitions[21]="([107]=3 [83]=3 [128]=3 [2]=3 [84]=3)"
literal_transitions[24]="([58]=22 [111]=22)"
local -A match_anything_transitions
match_anything_transitions=([2]=3 [1]=8 [7]=3 [16]=3 [11]=3 [6]=16 [15]=19 [8]=8 [3]=19 [17]=3 [13]=3 [12]=19)
match_anything_transitions=([7]=18 [8]=3 [1]=2 [23]=3 [6]=19 [5]=3 [3]=18 [19]=3 [12]=18 [9]=3 [10]=3 [14]=18 [11]=18 [2]=2)
declare -A subword_transitions
@@ -197,7 +214,7 @@ _hyprctl () {
fi
done
fi
local -A commands=([6]=1 [17]=2 [13]=3 [11]=0)
local -A commands=([8]=0 [23]=1 [9]=3 [6]=2)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
@@ -250,4 +267,8 @@ _hyprctl () {
return 0
}
compdef _hyprctl hyprctl
if [[ $ZSH_EVAL_CONTEXT =~ :file$ ]]; then
compdef _hyprctl hyprctl
else
_hyprctl
fi

View File

@@ -1,9 +1,9 @@
#include <ctype.h>
#include <cctype>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -12,7 +12,7 @@
#include <unistd.h>
#include <ranges>
#include <algorithm>
#include <signal.h>
#include <csignal>
#include <format>
#include <iostream>
@@ -22,8 +22,12 @@
#include <vector>
#include <deque>
#include <filesystem>
#include <stdarg.h>
#include <cstdarg>
#include <regex>
#include <sys/socket.h>
#include <hyprutils/string/String.hpp>
#include <cstring>
using namespace Hyprutils::String;
#include "Strings.hpp"
@@ -44,7 +48,7 @@ void log(std::string str) {
if (quiet)
return;
std::cout << str;
std::cout << str << "\n";
}
std::string getRuntimeDir() {
@@ -98,13 +102,53 @@ std::vector<SInstanceData> instances() {
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};
long 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);
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(), ' ');
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;
}
@@ -139,12 +183,17 @@ int request(std::string arg, int minArgs = 0) {
return 4;
}
if (needRoll)
return rollingRead(SERVERSOCKET);
std::string reply = "";
char buffer[8192] = {0};
sizeWritten = read(SERVERSOCKET, buffer, 8192);
if (sizeWritten < 0) {
if (errno == EWOULDBLOCK)
log("Hyprland IPC didn't respond in time\n");
log("Couldn't read (5)");
return 5;
}
@@ -238,12 +287,12 @@ void instancesRequest(bool json) {
std::vector<SInstanceData> inst = instances();
if (!json) {
for (auto& el : inst) {
for (auto const& el : inst) {
result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket);
}
} else {
result += '[';
for (auto& el : inst) {
for (auto const& el : inst) {
result += std::format(R"#(
{{
"instance": "{}",
@@ -270,12 +319,6 @@ std::deque<std::string> splitArgs(int argc, char** argv) {
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) {
bool parseArgs = true;
@@ -288,6 +331,7 @@ int main(int argc, char** argv) {
std::string fullArgs = "";
const auto ARGS = splitArgs(argc, argv);
bool json = false;
bool needRoll = false;
std::string overrideInstance = "";
for (std::size_t i = 0; i < ARGS.size(); ++i) {
@@ -307,6 +351,9 @@ int main(int argc, char** argv) {
fullArgs += "a";
} else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) {
fullArgs += "c";
} else if ((ARGS[i] == "-f" || ARGS[i] == "--follow") && !fullArgs.contains("f")) {
fullArgs += "f";
needRoll = true;
} else if (ARGS[i] == "--batch") {
fullRequest = "--batch ";
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
@@ -366,6 +413,11 @@ int main(int argc, char** argv) {
return 0;
}
if (needRoll && !fullRequest.contains("/rollinglog")) {
log("only 'rollinglog' command supports '--follow' option");
return 1;
}
if (overrideInstance.contains("_"))
instanceSignature = overrideInstance;
else if (!overrideInstance.empty()) {
@@ -425,6 +477,8 @@ int main(int argc, char** argv) {
exitStatus = request(fullRequest, 1);
else if (fullRequest.contains("/--help"))
std::cout << USAGE << std::endl;
else if (fullRequest.contains("/rollinglog") && needRoll)
exitStatus = request(fullRequest, 0, true);
else {
exitStatus = request(fullRequest);
}

View File

@@ -1,7 +1,26 @@
executable('hyprctl', 'main.cpp',
install: true
executable(
'hyprctl',
'main.cpp',
dependencies: [
dependency('hyprutils', version: '>= 0.1.1'),
],
install: true,
)
install_data('hyprctl.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprctl')
install_data('hyprctl.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime')
install_data('hyprctl.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprctl')
install_data(
'hyprctl.bash',
install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'),
install_tag: 'runtime',
rename: 'hyprctl',
)
install_data(
'hyprctl.fish',
install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'),
install_tag: 'runtime',
)
install_data(
'hyprctl.zsh',
install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'),
install_tag: 'runtime',
rename: '_hyprctl',
)

View File

@@ -4,4 +4,4 @@ Name: Hyprland
URL: https://github.com/hyprwm/Hyprland
Description: Hyprland header files
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)
pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1)
add_executable(hyprpm ${SRCFILES})
target_link_libraries(hyprpm PUBLIC PkgConfig::tomlplusplus)
target_link_libraries(hyprpm PUBLIC PkgConfig::deps)
# binary
install(TARGETS hyprpm)

View File

@@ -1,5 +1,9 @@
_hyprpm_cmd_0 () {
hyprpm list | grep Plugin | awk '{print $4}'
hyprpm list | awk '/Plugin/{print $4}'
}
_hyprpm_cmd_1 () {
hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//'
}
_hyprpm () {
@@ -11,16 +15,13 @@ _hyprpm () {
local words cword
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
local -a literals=("-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f")
declare -a literals=(--no-shallow -n ::= disable list --help update add --verbose -v --force -s remove enable --notify -h reload -f)
declare -A literal_transitions
literal_transitions[0]="([9]=6 [2]=2 [7]=6 [8]=6 [4]=6 [10]=2 [11]=3 [5]=2 [13]=6 [3]=3 [14]=2 [15]=6 [6]=2)"
literal_transitions[1]="([10]=2 [11]=3 [3]=3 [2]=2 [14]=2 [5]=2 [6]=2)"
literal_transitions[4]="([1]=5)"
literal_transitions[5]="([0]=6 [12]=6)"
declare -A match_anything_transitions
match_anything_transitions=([3]=2 [2]=4 [0]=1 [1]=1)
literal_transitions[0]="([0]=7 [3]=3 [4]=4 [8]=7 [9]=7 [6]=4 [7]=4 [11]=7 [5]=7 [10]=7 [12]=2 [13]=3 [15]=7 [16]=4 [17]=7)"
literal_transitions[1]="([12]=2 [13]=3 [3]=3 [4]=4 [16]=4 [6]=4 [7]=4)"
literal_transitions[5]="([2]=6)"
literal_transitions[6]="([1]=7 [14]=7)"
declare -A match_anything_transitions=([1]=1 [4]=5 [3]=4 [2]=4 [0]=1)
declare -A subword_transitions
local state=0
@@ -58,21 +59,9 @@ _hyprpm () {
done
local -a matches=()
local prefix="${words[$cword]}"
local shortest_suffix="$word"
for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
local char="${COMP_WORDBREAKS:$i:1}"
local candidate="${word##*$char}"
if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
shortest_suffix=$candidate
fi
done
local superfluous_prefix=""
if [[ "$shortest_suffix" != "$word" ]]; then
local superfluous_prefix=${word%$shortest_suffix}
fi
if [[ -v "literal_transitions[$state]" ]]; then
local state_transitions_initializer=${literal_transitions[$state]}
declare -A state_transitions
@@ -81,25 +70,38 @@ _hyprpm () {
for literal_id in "${!state_transitions[@]}"; do
local literal="${literals[$literal_id]}"
if [[ $literal = "${prefix}"* ]]; then
local completion=${literal#"$superfluous_prefix"}
COMPREPLY+=("$completion ")
matches+=("$literal ")
fi
done
fi
declare -A commands
commands=([3]=0)
commands=([3]=0 [2]=1)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
local completions=()
mapfile -t completions < <(_hyprpm_cmd_${command_id} "$prefix" | cut -f1)
readarray -t completions < <(_hyprpm_cmd_${command_id} "$prefix" | cut -f1)
for item in "${completions[@]}"; do
if [[ $item = "${prefix}"* ]]; then
COMPREPLY+=("$item")
matches+=("$item")
fi
done
fi
local shortest_suffix="$prefix"
for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
local char="${COMP_WORDBREAKS:$i:1}"
local candidate=${prefix##*$char}
if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
shortest_suffix=$candidate
fi
done
local superfluous_prefix=""
if [[ "$shortest_suffix" != "$prefix" ]]; then
local superfluous_prefix=${prefix%$shortest_suffix}
fi
COMPREPLY=("${matches[@]#$superfluous_prefix}")
return 0
}

View File

@@ -1,6 +1,11 @@
function _hyprpm_1
set 1 $argv[1]
hyprpm list | grep Plugin | awk '{print $4}'
hyprpm list | awk '/Plugin/{print $4}'
end
function _hyprpm_2
set 1 $argv[1]
hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//'
end
function _hyprpm
@@ -14,49 +19,51 @@ function _hyprpm
set COMP_CWORD (count $COMP_WORDS)
end
set --local literals "-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f"
set literals "--no-shallow" "-n" "::=" "disable" "list" "--help" "update" "add" "--verbose" "-v" "--force" "-s" "remove" "enable" "--notify" "-h" "reload" "-f"
set --local descriptions
set descriptions[1] "Send a hyprland notification for important events (e.g. load fail)"
set descriptions[3] "List all installed plugins"
set descriptions
set descriptions[1] "Disable shallow cloning of Hyprland sources"
set descriptions[2] "Send a hyprland notification for important events (e.g. load fail)"
set descriptions[4] "Unload a plugin"
set descriptions[5] "Show help menu"
set descriptions[6] "Check and update all plugins if needed"
set descriptions[7] "Install a new plugin repository from git"
set descriptions[8] "Enable too much loggin"
set descriptions[5] "List all installed plugins"
set descriptions[6] "Show help menu"
set descriptions[7] "Check and update all plugins if needed"
set descriptions[8] "Install a new plugin repository from git"
set descriptions[9] "Enable too much loggin"
set descriptions[10] "Force an operation ignoring checks (e.g. update -f)"
set descriptions[11] "Remove a plugin repository"
set descriptions[12] "Load a plugin"
set descriptions[13] "Send a hyprland notification for important events (e.g. load fail)"
set descriptions[14] "Show help menu"
set descriptions[15] "Reload all plugins"
set descriptions[16] "Force an operation ignoring checks (e.g. update -f)"
set descriptions[10] "Enable too much loggin"
set descriptions[11] "Force an operation ignoring checks (e.g. update -f)"
set descriptions[12] "Disable shallow cloning of Hyprland sources"
set descriptions[13] "Remove a plugin repository"
set descriptions[14] "Load a plugin"
set descriptions[15] "Send a hyprland notification for important events (e.g. load fail)"
set descriptions[16] "Show help menu"
set descriptions[17] "Reload all plugins"
set descriptions[18] "Force an operation ignoring checks (e.g. update -f)"
set --local literal_transitions
set literal_transitions[1] "set inputs 10 3 8 9 5 11 12 6 14 4 15 16 7; set tos 7 3 7 7 7 3 4 3 7 4 3 7 3"
set literal_transitions[2] "set inputs 11 12 4 3 15 6 7; set tos 3 4 4 3 3 3 3"
set literal_transitions[5] "set inputs 2; set tos 6"
set literal_transitions[6] "set inputs 1 13; set tos 7 7"
set literal_transitions
set literal_transitions[1] "set inputs 1 4 5 9 10 7 8 12 6 11 13 14 16 17 18; set tos 8 4 5 8 8 5 5 8 8 8 3 4 8 5 8"
set literal_transitions[2] "set inputs 13 14 4 5 17 7 8; set tos 3 4 4 5 5 5 5"
set literal_transitions[6] "set inputs 3; set tos 7"
set literal_transitions[7] "set inputs 2 15; set tos 8 8"
set --local match_anything_transitions_from 4 3 1 2
set --local match_anything_transitions_to 3 5 2 2
set match_anything_transitions_from 2 5 4 3 1
set match_anything_transitions_to 2 6 5 5 2
set --local state 1
set --local word_index 2
set state 1
set word_index 2
while test $word_index -lt $COMP_CWORD
set --local -- word $COMP_WORDS[$word_index]
set -- word $COMP_WORDS[$word_index]
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
set --local --erase inputs
set --local --erase tos
set --erase inputs
set --erase tos
eval $literal_transitions[$state]
if contains -- $word $literals
set --local literal_matched 0
set literal_matched 0
for literal_id in (seq 1 (count $literals))
if test $literals[$literal_id] = $word
set --local index (contains --index -- $literal_id $inputs)
set index (contains --index -- $literal_id $inputs)
set state $tos[$index]
set word_index (math $word_index + 1)
set literal_matched 1
@@ -70,7 +77,7 @@ function _hyprpm
end
if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state]
set --local index (contains --index -- $state $match_anything_transitions_from)
set index (contains --index -- $state $match_anything_transitions_from)
set state $match_anything_transitions_to[$index]
set word_index (math $word_index + 1)
continue
@@ -80,8 +87,8 @@ function _hyprpm
end
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
set --local --erase inputs
set --local --erase tos
set --erase inputs
set --erase tos
eval $literal_transitions[$state]
for literal_id in $inputs
if test -n $descriptions[$literal_id]
@@ -92,14 +99,14 @@ function _hyprpm
end
end
set command_states 4
set command_ids 1
set command_states 4 3
set command_ids 1 2
if contains $state $command_states
set --local index (contains --index $state $command_states)
set --local function_id $command_ids[$index]
set --local function_name _hyprpm_$function_id
set --local --erase inputs
set --local --erase tos
set index (contains --index $state $command_states)
set function_id $command_ids[$index]
set function_name _hyprpm_$function_id
set --erase inputs
set --erase tos
$function_name "$COMP_WORDS[$COMP_CWORD]"
end

View File

@@ -5,10 +5,11 @@ hyprpm [<FLAGS>]... <ARGUMENT>
| (--help | -h) "Show help menu"
| (--verbose | -v) "Enable too much loggin"
| (--force | -f) "Force an operation ignoring checks (e.g. update -f)"
| (--no-shallow | -s) "Disable shallow cloning of Hyprland sources"
;
<ARGUMENT> ::= (add) "Install a new plugin repository from git"
| (remove) "Remove a plugin repository"
| (remove <PLUGIN_REPOS>) "Remove a plugin repository"
| (update) "Check and update all plugins if needed"
| (list) "List all installed plugins"
| (enable <PLUGINS>) "Load a plugin"
@@ -16,4 +17,5 @@ hyprpm [<FLAGS>]... <ARGUMENT>
| (reload) "Reload all plugins"
;
<PLUGINS> ::= {{{ hyprpm list | grep Plugin | awk '{print $4}' }}};
<PLUGINS> ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}};
<PLUGIN_REPOS> ::= {{{ hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' }}};

View File

@@ -1,37 +1,43 @@
#compdef hyprpm
_hyprpm_cmd_0 () {
hyprpm list | grep Plugin | awk '{print $4}'
hyprpm list | awk '/Plugin/{print $4}'
}
_hyprpm_cmd_1 () {
hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//'
}
_hyprpm () {
local -a literals=("-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f")
local -a literals=("--no-shallow" "-n" "::=" "disable" "list" "--help" "update" "add" "--verbose" "-v" "--force" "-s" "remove" "enable" "--notify" "-h" "reload" "-f")
local -A descriptions
descriptions[1]="Send a hyprland notification for important events (e.g. load fail)"
descriptions[3]="List all installed plugins"
descriptions[1]="Disable shallow cloning of Hyprland sources"
descriptions[2]="Send a hyprland notification for important events (e.g. load fail)"
descriptions[4]="Unload a plugin"
descriptions[5]="Show help menu"
descriptions[6]="Check and update all plugins if needed"
descriptions[7]="Install a new plugin repository from git"
descriptions[8]="Enable too much loggin"
descriptions[5]="List all installed plugins"
descriptions[6]="Show help menu"
descriptions[7]="Check and update all plugins if needed"
descriptions[8]="Install a new plugin repository from git"
descriptions[9]="Enable too much loggin"
descriptions[10]="Force an operation ignoring checks (e.g. update -f)"
descriptions[11]="Remove a plugin repository"
descriptions[12]="Load a plugin"
descriptions[13]="Send a hyprland notification for important events (e.g. load fail)"
descriptions[14]="Show help menu"
descriptions[15]="Reload all plugins"
descriptions[16]="Force an operation ignoring checks (e.g. update -f)"
descriptions[10]="Enable too much loggin"
descriptions[11]="Force an operation ignoring checks (e.g. update -f)"
descriptions[12]="Disable shallow cloning of Hyprland sources"
descriptions[13]="Remove a plugin repository"
descriptions[14]="Load a plugin"
descriptions[15]="Send a hyprland notification for important events (e.g. load fail)"
descriptions[16]="Show help menu"
descriptions[17]="Reload all plugins"
descriptions[18]="Force an operation ignoring checks (e.g. update -f)"
local -A literal_transitions
literal_transitions[1]="([10]=7 [3]=3 [8]=7 [9]=7 [5]=7 [11]=3 [12]=4 [6]=3 [14]=7 [4]=4 [15]=3 [16]=7 [7]=3)"
literal_transitions[2]="([11]=3 [12]=4 [4]=4 [3]=3 [15]=3 [6]=3 [7]=3)"
literal_transitions[5]="([2]=6)"
literal_transitions[6]="([1]=7 [13]=7)"
literal_transitions[1]="([1]=8 [4]=4 [5]=5 [9]=8 [10]=8 [7]=5 [8]=5 [12]=8 [6]=8 [11]=8 [13]=3 [14]=4 [16]=8 [17]=5 [18]=8)"
literal_transitions[2]="([13]=3 [14]=4 [4]=4 [5]=5 [17]=5 [7]=5 [8]=5)"
literal_transitions[6]="([3]=7)"
literal_transitions[7]="([2]=8 [15]=8)"
local -A match_anything_transitions
match_anything_transitions=([4]=3 [3]=5 [1]=2 [2]=2)
match_anything_transitions=([2]=2 [5]=6 [4]=5 [3]=5 [1]=2)
declare -A subword_transitions
@@ -91,7 +97,7 @@ _hyprpm () {
fi
done
fi
local -A commands=([4]=0)
local -A commands=([4]=0 [3]=1)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}

View File

@@ -49,7 +49,7 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
{"rev", repo.rev}
}}
};
for (auto& p : repo.plugins) {
for (auto const& p : repo.plugins) {
// copy .so to the good place
if (std::filesystem::exists(p.filename))
std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so");

View File

@@ -6,7 +6,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
auto manifest = toml::parse_file(path);
if (type == MANIFEST_HYPRLOAD) {
for (auto& [key, val] : manifest) {
for (auto const& [key, val] : manifest) {
if (key.str().ends_with(".build"))
continue;
@@ -63,7 +63,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
}
}
for (auto& [key, val] : manifest) {
for (auto const& [key, val] : manifest) {
if (key.str() == "repository")
continue;

View File

@@ -19,30 +19,15 @@
#include <toml++/toml.hpp>
static std::string removeBeginEndSpacesTabs(std::string str) {
if (str.empty())
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;
}
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
static std::string execAndGet(std::string cmd) {
cmd += " 2>&1";
std::array<char, 128> buffer;
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)
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";
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;
@@ -216,9 +204,9 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.m_iSteps = 2;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:");
for (auto& pl : pManifest->m_vPlugins) {
for (auto const& pl : pManifest->m_vPlugins) {
std::string message = std::string{Colors::RESET} + "" + pl.name + " by ";
for (auto& a : pl.authors) {
for (auto const& a : pl.authors) {
message += a + ", ";
}
if (pl.authors.size() > 0) {
@@ -234,13 +222,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) {
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash)
continue;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
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;
}
}
@@ -270,7 +264,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) {
for (auto const& bs : p.buildSteps) {
std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
}
@@ -305,7 +299,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
repo.url = url;
repo.rev = rev;
repo.hash = repohash;
for (auto& p : pManifest->m_vPlugins) {
for (auto const& p : pManifest->m_vPlugins) {
repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed});
}
DataState::addNewPluginRepo(repo);
@@ -371,10 +365,10 @@ eHeadersErrors CPluginManager::headersValid() {
else
headers = "";
if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland"))
if (PATH.ends_with("protocols"))
continue;
verHeader = removeBeginEndSpacesTabs(PATH.substr(2)) + "/hyprland/src/version.h";
verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h";
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.");
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
// due to timezones, etc.
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)
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.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)
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)
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)
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.
std::string missing = ret.substr(ret.find("The following required packages were not found:"));
missing = missing.substr(0, missing.find("Call Stack"));
std::string missing = ret.substr(ret.find("CMake Error at"));
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'));
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;
}
// 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.m_iSteps = 4;
progress.m_szCurrentMessage = "Installing sources";
@@ -537,7 +539,8 @@ bool CPluginManager::updateHeaders(bool force) {
std::cout << "\n";
} 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_szCurrentMessage = "Failed";
progress.print();
@@ -576,7 +579,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
const std::string USERNAME = getpwuid(getuid())->pw_name;
m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME;
for (auto& repo : REPOS) {
for (auto const& repo : REPOS) {
bool update = forceUpdateAll;
progress.m_iSteps++;
@@ -655,7 +658,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) {
for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) {
if (hl != HLVER.hash)
continue;
@@ -676,7 +679,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) {
for (auto const& bs : p.buildSteps) {
std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs);
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
}
@@ -706,7 +709,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (repohash.length() > 0)
repohash.pop_back();
newrepo.hash = repohash;
for (auto& p : pManifest->m_vPlugins) {
for (auto const& p : pManifest->m_vPlugins) {
const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; });
newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false});
}
@@ -791,8 +794,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
const auto REPOS = DataState::getAllRepositories();
auto enabled = [REPOS](const std::string& plugin) -> bool {
for (auto& r : REPOS) {
for (auto& p : r.plugins) {
for (auto const& r : REPOS) {
for (auto const& p : r.plugins) {
if (p.name == plugin && p.enabled)
return true;
}
@@ -802,8 +805,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
};
auto repoForName = [REPOS](const std::string& name) -> std::string {
for (auto& r : REPOS) {
for (auto& p : r.plugins) {
for (auto const& r : REPOS) {
for (auto const& p : r.plugins) {
if (p.name == name)
return r.name;
}
@@ -813,7 +816,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
};
// unload disabled plugins
for (auto& p : loadedPlugins) {
for (auto const& p : loadedPlugins) {
if (!enabled(p)) {
// unload
loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false);
@@ -822,8 +825,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() {
}
// load enabled plugins
for (auto& r : REPOS) {
for (auto& p : r.plugins) {
for (auto const& r : REPOS) {
for (auto const& p : r.plugins) {
if (!p.enabled)
continue;
@@ -852,10 +855,10 @@ bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) {
void CPluginManager::listAllPlugins() {
const auto REPOS = DataState::getAllRepositories();
for (auto& r : REPOS) {
for (auto const& r : REPOS) {
std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n";
for (auto& p : r.plugins) {
for (auto const& p : r.plugins) {
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
@@ -888,10 +891,22 @@ 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";
}
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() {
std::vector<std::string> deps = {"meson", "cpio", "cmake"};
for (auto& d : deps) {
if (!execAndGet("which " + d + " 2>&1").contains("/"))
std::vector<std::string> deps = {"meson", "cpio", "cmake", "pkg-config"};
for (auto const& d : deps) {
if (!execAndGet("command -v " + d).contains("/"))
return false;
}

View File

@@ -59,12 +59,14 @@ class CPluginManager {
bool hasDeps();
bool m_bVerbose = false;
bool m_bNoShallow = false;
// will delete recursively if exists!!
bool createSafeDirectory(const std::string& path);
private:
std::string headerError(const eHeadersErrors err);
std::string headerErrorShort(const eHeadersErrors err);
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
--verbose | -v Enable too much logging
--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;
bool notify = false, verbose = false, force = false;
bool notify = false, verbose = false, force = false, noShallow = false;
for (int i = 1; i < argc; ++i) {
if (ARGS[i].starts_with("-")) {
@@ -52,6 +53,8 @@ int main(int argc, char** argv, char** envp) {
notify = true;
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
verbose = true;
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
noShallow = true;
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
force = true;
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
@@ -71,6 +74,7 @@ int main(int argc, char** argv, char** envp) {
g_pPluginManager = std::make_unique<CPluginManager>();
g_pPluginManager->m_bVerbose = verbose;
g_pPluginManager->m_bNoShallow = noShallow;
if (command[0] == "add") {
if (command.size() < 2) {

View File

@@ -1,14 +1,31 @@
globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
src = globber.stdout().strip().split('\n')
executable('hyprpm', src,
executable(
'hyprpm',
src,
dependencies: [
dependency('hyprutils', version: '>= 0.1.1'),
dependency('threads'),
dependency('tomlplusplus')
dependency('tomlplusplus'),
],
install : true
install: true,
)
install_data('../hyprpm.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprpm')
install_data('../hyprpm.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime')
install_data('../hyprpm.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprpm')
install_data(
'../hyprpm.bash',
install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'),
install_tag: 'runtime',
rename: 'hyprpm',
)
install_data(
'../hyprpm.fish',
install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'),
install_tag: 'runtime',
)
install_data(
'../hyprpm.zsh',
install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'),
install_tag: 'runtime',
rename: '_hyprpm',
)

View File

@@ -1,31 +1,38 @@
project('Hyprland', 'cpp', 'c',
version : run_command('jq', '-r', '.version', join_paths(meson.source_root(), 'props.json'), check: true).stdout().strip(),
default_options : [
project(
'Hyprland',
'cpp',
'c',
version: run_command('cat', join_paths(meson.project_source_root(), 'VERSION'), check: true).stdout().strip(),
default_options: [
'warning_level=2',
'default_library=static',
'optimization=3',
'buildtype=release',
'debug=false',
'cpp_std=c++23',
])
'cpp_std=c++26',
],
)
datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"'
add_project_arguments(
[
'-Wno-unused-parameter',
'-Wno-unused-value',
'-Wno-missing-field-initializers',
'-Wno-narrowing',
'-Wno-pointer-arith',
'-Wno-pointer-arith', datarootdir,
],
language: 'cpp')
language: 'cpp',
)
cpp_compiler = meson.get_compiler('cpp')
if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif
wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2'])
have_xwlr = wlroots.get_variable('features').get('xwayland')
aquamarine = dependency('aquamarine')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
xcb_dep = dependency('xcb', required: get_option('xwayland'))
xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland'))
xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland'))
@@ -34,22 +41,16 @@ xcb_render_dep = dependency('xcb-render', required: get_option('xwayland'))
xcb_res_dep = dependency('xcb-res', required: get_option('xwayland'))
xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland'))
cmake = import('cmake')
udis = cmake.subproject('udis86')
udis86 = udis.dependency('libudis86')
gio_dep = dependency('gio-2.0', required: true)
if get_option('xwayland').enabled() and not have_xwlr
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
if not xcb_dep.found()
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs
# Handle options
if get_option('systemd').enabled()
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
endif
@@ -62,14 +63,22 @@ if get_option('buildtype') == 'debug'
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
endif
version_h = run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
# Generate hyprland version and populate version.h
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
# Install headers
globber = run_command('find', 'src', '-name', '*.h*', check: true)
headers = globber.stdout().strip().split('\n')
foreach file : headers
install_headers(file, subdir: 'hyprland', preserve_path: true)
endforeach
tracy = dependency('tracy', static: true, required: get_option('tracy_enable'))
if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized'
warning('Profiling builds should set -- buildtype = debugoptimized')
endif
subdir('protocols')
subdir('src')
subdir('hyprctl')
@@ -78,6 +87,7 @@ subdir('assets')
subdir('example')
subdir('docs')
# Generate hyprland.pc
pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')
import('pkgconfig').generate(
@@ -86,5 +96,5 @@ import('pkgconfig').generate(
url: 'https://github.com/hyprwm/Hyprland',
description: 'Hyprland header files',
install_dir: pkg_install_dir,
subdirs: ['', 'hyprland/protocols', 'hyprland', 'hyprland/wlr'],
subdirs: ['', 'hyprland/protocols', 'hyprland'],
)

View File

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

View File

@@ -1,42 +1,36 @@
{
lib,
stdenv,
stdenvAdapters,
pkg-config,
pkgconf,
makeWrapper,
cmake,
meson,
ninja,
aquamarine,
binutils,
cairo,
expat,
fribidi,
git,
hyprcursor,
hyprland-protocols,
hyprlang,
hyprutils,
hyprwayland-scanner,
jq,
libGL,
libdatrie,
libdrm,
libexecinfo,
libinput,
libselinux,
libsepol,
libthai,
libuuid,
libxkbcommon,
libuuid,
mesa,
pango,
pciutils,
pcre2,
python3,
systemd,
tomlplusplus,
udis86,
udis86-hyprland,
wayland,
wayland-protocols,
wayland-scanner,
wlroots,
xorg,
xwayland,
debug ? false,
@@ -46,25 +40,39 @@
wrapRuntimeDeps ? true,
version ? "git",
commit,
revCount,
date,
# deprecated flags
enableNvidiaPatches ? false,
nvidiaPatches ? false,
hidpiXWayland ? false,
}:
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
stdenv.mkDerivation {
pname = "hyprland${lib.optionalString debug "-debug"}";
}: let
inherit (builtins) baseNameOf foldl';
inherit (lib.asserts) assertMsg;
inherit (lib.attrsets) mapAttrsToList;
inherit (lib.lists) flatten concatLists optional optionals;
inherit (lib.sources) cleanSourceWith cleanSource;
inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable;
adapters = flatten [
stdenvAdapters.useMoldLinker
];
customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters;
in
assert assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
assert assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
assert assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
customStdenv.mkDerivation {
pname = "hyprland${optionalString debug "-debug"}";
inherit version;
src = lib.cleanSourceWith {
src = cleanSourceWith {
filter = name: type: let
baseName = baseNameOf (toString name);
in
! (lib.hasSuffix ".nix" baseName);
src = lib.cleanSource ../.;
! (hasSuffix ".nix" baseName);
src = cleanSource ../.;
};
postPatch = ''
@@ -75,23 +83,21 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
sed -i "s#@PREFIX@/##g" hyprland.pc.in
'';
COMMITS = revCount;
DATE = date;
DIRTY = optionalString (commit == "") "dirty";
HASH = commit;
DIRTY = if commit == "" then "dirty" else "";
nativeBuildInputs = lib.concatLists [
[
depsBuildBuild = [
pkg-config
];
nativeBuildInputs = [
hyprwayland-scanner
jq
makeWrapper
cmake
meson
ninja
pkg-config
python3
wayland-scanner
]
# introduce this later so that cmake takes precedence
wlroots.nativeBuildInputs
];
outputs = [
@@ -100,59 +106,66 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
"dev"
];
buildInputs = lib.concatLists [
wlroots.buildInputs
udis86.buildInputs
buildInputs = concatLists [
[
aquamarine
cairo
expat
fribidi
git
hyprcursor.dev
hyprcursor
hyprland-protocols
hyprlang
libGL
hyprutils
libdrm
libdatrie
libGL
libinput
libselinux
libsepol
libthai
libuuid
libxkbcommon
mesa
pango
pciutils
pcre2
tomlplusplus
udis86-hyprland
wayland
wayland-protocols
wayland-scanner
xorg.libXcursor
]
(lib.optionals stdenv.hostPlatform.isMusl [libexecinfo])
(lib.optionals enableXWayland [
(optionals customStdenv.hostPlatform.isMusl [libexecinfo])
(optionals enableXWayland [
xorg.libxcb
xorg.libXdmcp
xorg.xcbutil
xorg.xcbutilerrors
xorg.xcbutilrenderutil
xorg.xcbutilwm
xwayland
])
(lib.optionals withSystemd [systemd])
(optional withSystemd systemd)
];
cmakeBuildType =
mesonBuildType =
if debug
then "Debug"
else "RelWithDebInfo";
then "debugoptimized"
else "release";
cmakeFlags = [
(lib.cmakeBool "NO_XWAYLAND" (!enableXWayland))
(lib.cmakeBool "LEGACY_RENDERER" legacyRenderer)
(lib.cmakeBool "NO_SYSTEMD" (!withSystemd))
# we want as much debug info as possible
dontStrip = debug;
mesonFlags = flatten [
(mapAttrsToList mesonEnable {
"xwayland" = enableXWayland;
"legacy_renderer" = legacyRenderer;
"systemd" = withSystemd;
})
(mapAttrsToList mesonBool {
"b_pch" = false;
"tracy_enable" = false;
})
];
postInstall = ''
${lib.optionalString wrapRuntimeDeps ''
${optionalString wrapRuntimeDeps ''
wrapProgram $out/bin/Hyprland \
--suffix PATH : ${lib.makeBinPath [
--suffix PATH : ${makeBinPath [
binutils
pciutils
pkgconf
@@ -162,11 +175,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
passthru.providedSessions = ["hyprland"];
meta = with lib; {
meta = {
homepage = "https://github.com/hyprwm/Hyprland";
description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
license = licenses.bsd3;
platforms = wlroots.meta.platforms;
description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
license = lib.licenses.bsd3;
platforms = lib.platforms.linux;
mainProgram = "Hyprland";
};
}

View File

@@ -3,13 +3,12 @@
lib,
inputs,
}: let
props = builtins.fromJSON (builtins.readFile ../props.json);
mkDate = longDate: (lib.concatStringsSep "-" [
(builtins.substring 0 4 longDate)
(builtins.substring 4 2 longDate)
(builtins.substring 6 2 longDate)
]);
version = lib.removeSuffix "\n" (builtins.readFile ../VERSION);
in {
# Contains what a user is most likely to care about:
# Hyprland itself, XDPH and the Share Picker.
@@ -21,19 +20,23 @@ in {
# Packages for variations of Hyprland, dependencies included.
hyprland-packages = lib.composeManyExtensions [
# Dependencies
inputs.aquamarine.overlays.default
inputs.hyprcursor.overlays.default
inputs.hyprland-protocols.overlays.default
inputs.hyprlang.overlays.default
inputs.hyprutils.overlays.default
inputs.hyprwayland-scanner.overlays.default
self.overlays.xwayland
self.overlays.udis86
# Hyprland packages themselves
(final: prev: let
date = mkDate (self.lastModifiedDate or "19700101");
in {
hyprland = final.callPackage ./default.nix {
stdenv = final.gcc13Stdenv;
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
stdenv = final.gcc14Stdenv;
version = "${version}+date=${date}_${self.shortRev or "dirty"}";
commit = self.rev or "";
revCount = self.sourceInfo.revCount or "";
inherit date;
};
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
@@ -63,13 +66,19 @@ in {
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
'';
# udis86 from nixpkgs is too old, and also does not provide a .pc file
# this version is the one used in the git submodule, and allows us to
# fetch the source without '?submodules=1'
udis86 = final: prev: {
udis86-hyprland = prev.udis86.overrideAttrs (self: super: {
src = final.fetchFromGitHub {
owner = "canihavesomecoffee";
repo = "udis86";
rev = "5336633af70f3917760a6d441ff02d93477b0c86";
hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g=";
};
patches = [];
});
};
}

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

@@ -1,100 +1,76 @@
wayland_protos = dependency('wayland-protocols',
wayland_protos = dependency(
'wayland-protocols',
version: '>=1.32',
fallback: 'wayland-protocols',
default_options: ['tests=false'],
)
hyprland_protos = dependency('hyprland-protocols',
hyprland_protos = dependency(
'hyprland-protocols',
version: '>=0.2',
fallback: 'hyprland-protocols',
)
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
wayland_protocol_dir = wayland_protos.get_variable('pkgdatadir')
hyprland_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.10', native: true)
hyprwayland_scanner = find_program(
hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'),
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']
'wlr-gamma-control-unstable-v1.xml',
'wlr-foreign-toplevel-management-unstable-v1.xml',
'wlr-output-power-management-unstable-v1.xml',
'input-method-unstable-v2.xml',
'virtual-keyboard-unstable-v1.xml',
'wlr-virtual-pointer-unstable-v1.xml',
'wlr-output-management-unstable-v1.xml',
'kde-server-decoration.xml',
'wlr-layer-shell-unstable-v1.xml',
'wayland-drm.xml',
'wlr-data-control-unstable-v1.xml',
'wlr-screencopy-unstable-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml',
wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml',
wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
wayland_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
wayland_protocol_dir / 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml',
wayland_protocol_dir / 'unstable/relative-pointer/relative-pointer-unstable-v1.xml',
wayland_protocol_dir / 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml',
wayland_protocol_dir / 'staging/alpha-modifier/alpha-modifier-v1.xml',
wayland_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml',
wayland_protocol_dir / 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml',
wayland_protocol_dir / 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml',
wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml',
wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v1.xml',
wayland_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
wayland_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml',
wayland_protocol_dir / 'staging/ext-idle-notify/ext-idle-notify-v1.xml',
wayland_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml',
wayland_protocol_dir / 'stable/tablet/tablet-v2.xml',
wayland_protocol_dir / 'stable/presentation-time/presentation-time.xml',
wayland_protocol_dir / 'stable/xdg-shell/xdg-shell.xml',
wayland_protocol_dir / 'unstable/primary-selection/primary-selection-unstable-v1.xml',
wayland_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml',
wayland_protocol_dir / 'stable/viewporter/viewporter.xml',
wayland_protocol_dir / 'stable/linux-dmabuf/linux-dmabuf-v1.xml',
wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml',
wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml',
wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml',
]
new_protocols = [
['wlr-gamma-control-unstable-v1.xml'],
['wlr-foreign-toplevel-management-unstable-v1.xml'],
['wlr-output-power-management-unstable-v1.xml'],
['input-method-unstable-v2.xml'],
['virtual-keyboard-unstable-v1.xml'],
['wlr-virtual-pointer-unstable-v1.xml'],
['wlr-output-management-unstable-v1.xml'],
['kde-server-decoration.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['wayland-drm.xml'],
['wlr-data-control-unstable-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/fractional-scale/fractional-scale-v1.xml'],
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
[wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'],
[wl_protocol_dir, 'staging/alpha-modifier/alpha-modifier-v1.xml'],
[wl_protocol_dir, 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-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/text-input/text-input-unstable-v3.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/ext-idle-notify/ext-idle-notify-v1.xml'],
[wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'],
[wl_protocol_dir, 'stable/tablet/tablet-v2.xml'],
[wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'],
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
[wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'],
[wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'],
[wl_protocol_dir, 'stable/viewporter/viewporter.xml'],
[wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'],
]
wl_protos_src = []
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 = []
foreach p : new_protocols
xml = join_paths(p)
new_wl_protos += custom_target(
xml.underscorify(),
input: xml,
wl_protocols = []
foreach protocol : protocols
wl_protocols += custom_target(
protocol.underscorify(),
input: protocol,
install: true,
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
@@ -102,30 +78,26 @@ foreach p : new_protocols
)
endforeach
wayland_server_dep = dependency('wayland-server', version: '>=1.20.0')
wayland_server_dir = wayland_server_dep.get_variable('pkgdatadir')
# wayland.xml generation
wayland_scanner = dependency('wayland-scanner')
wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir')
wl_server_protos = [
wayland_server_dir / 'wayland.xml'
]
wl_server_protos_gen = []
foreach p : wl_server_protos
wl_server_protos_gen += custom_target(
p.underscorify(),
input: p,
install: false,
wayland_xml = wayland_scanner_datadir / 'wayland.xml'
wayland_protocol = custom_target(
wayland_xml.underscorify(),
input: wayland_xml,
install: true,
install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')],
output: ['@BASENAME@.cpp', '@BASENAME@.hpp'],
command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'],
)
endforeach
)
lib_server_protos = static_library(
'server_protos',
wl_protos_src + wl_protos_headers + new_wl_protos + wl_server_protos_gen,
dependencies: wayland_server_dep.partial_dependency(compile_args: true),
wl_protocols + wayland_protocol,
)
server_protos = declare_dependency(
link_with: lib_server_protos,
sources: wl_protos_headers + new_wl_protos,
sources: wl_protocols + wayland_protocol,
)

View File

@@ -1,8 +1,8 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f54cdf5d..ad7c3e73 100755
index f26a5c3c..3dfef333 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -130,6 +130,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
@@ -143,6 +143,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Enabling ASan")
target_link_libraries(Hyprland asan)

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
#include <memory>
#include <deque>
#include <list>
#include <sys/resource.h>
#include "defines.hpp"
#include "debug/Log.hpp"
@@ -29,6 +30,9 @@
#include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp"
#include <aquamarine/backend/Backend.hpp>
#include <aquamarine/output/Output.hpp>
class CWLSurfaceResource;
enum eManagersInitStage {
@@ -42,22 +46,11 @@ class CCompositor {
CCompositor();
~CCompositor();
// ------------------ WLR BASICS ------------------ //
wl_display* m_sWLDisplay;
wl_event_loop* m_sWLEventLoop;
wlr_backend* m_sWLRBackend;
wlr_session* m_sWLRSession;
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;
// ------------------------------------------------- //
int m_iDRMFD = -1;
bool m_bInitialized = false;
SP<Aquamarine::CBackend> m_pAqBackend;
std::string m_szHyprTempDataRoot = "";
@@ -74,13 +67,16 @@ class CCompositor {
std::vector<PHLWINDOWREF> m_vWindowsFadingOut;
std::vector<PHLLSREF> m_vSurfacesFadingOut;
std::unordered_map<std::string, uint64_t> m_mMonitorIDMap;
std::unordered_map<std::string, MONITORID> m_mMonitorIDMap;
void initServer();
void initServer(std::string socketName, int socketFd);
void startCompositor();
void stopCompositor();
void cleanup();
void createLockFile();
void removeLockFile();
void bumpNofile();
void restoreNofile();
WP<CWLSurfaceResource> m_pLastFocus;
PHLWINDOWREF m_pLastWindow;
@@ -92,14 +88,16 @@ class CCompositor {
bool m_bSessionActive = true;
bool m_bDPMSStateON = true;
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
bool m_bExitTriggered = false; // For exit dispatcher
bool m_bIsShuttingDown = false;
bool m_bFinalRequests = false;
bool m_bDesktopEnvSet = false;
bool m_bEnableXwayland = true;
// ------------------------------------------------- //
CMonitor* getMonitorFromID(const int&);
CMonitor* getMonitorFromID(const MONITORID&);
CMonitor* getMonitorFromName(const std::string&);
CMonitor* getMonitorFromDesc(const std::string&);
CMonitor* getMonitorFromCursor();
@@ -113,60 +111,67 @@ class CCompositor {
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
CMonitor* getMonitorFromOutput(wlr_output*);
CMonitor* getRealMonitorFromOutput(wlr_output*);
CMonitor* getMonitorFromOutput(SP<Aquamarine::IOutput>);
CMonitor* getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE);
PHLWORKSPACE getWorkspaceByID(const int&);
bool isWorkspaceVisibleNotCovered(PHLWORKSPACE);
PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&);
PHLWORKSPACE getWorkspaceByName(const std::string&);
PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&);
void updateWorkspaceSpecialRenderData(const int&);
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 = {});
void updateWorkspaceWindowDecos(const WORKSPACEID&);
void updateWorkspaceWindowData(const WORKSPACEID&);
int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional<bool> onlyTiled = {}, std::optional<bool> onlyVisible = {});
PHLWINDOW getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const int&);
PHLWINDOW getFirstWindowOnWorkspace(const int&);
PHLWINDOW getTopLeftWindowOnWorkspace(const int&);
PHLWINDOW getFullscreenWindowOnWorkspace(const int&);
bool hasUrgentWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&);
PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&);
bool isWindowActive(PHLWINDOW);
void changeWindowZOrder(PHLWINDOW, bool);
void cleanupFadingOut(const int& monid);
void cleanupFadingOut(const MONITORID& monid);
PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
int getNextAvailableNamedWorkspace();
WORKSPACEID getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
CMonitor* getMonitorInDirection(const char&);
CMonitor* getMonitorInDirection(CMonitor*, const char&);
void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const int64_t& id);
void updateWorkspaceWindows(const WORKSPACEID& id);
void updateWindowAnimatedDecorationValues(PHLWINDOW);
int getNextAvailableMonitorID(std::string const& name);
MONITORID getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&);
void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID);
bool workspaceIDOutOfBounds(const WORKSPACEID&);
void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state);
void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
PHLWINDOW getX11Parent(PHLWINDOW);
void scheduleFrameForMonitor(CMonitor*);
void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN);
void addToFadingOutSafe(PHLLS);
void removeFromFadingOutSafe(PHLLS);
void addToFadingOutSafe(PHLWINDOW);
PHLWINDOW getWindowByRegex(const std::string&);
void warpCursorTo(const Vector2D&, bool force = false);
PHLLS getLayerSurfaceFromSurface(SP<CWLSurfaceResource>);
void closeWindow(PHLWINDOW);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const int&);
PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused!
void renameWorkspace(const int&, const std::string& name = "");
void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&);
PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "",
bool isEmpty = true); // will be deleted next frame if left empty and unfocused!
void renameWorkspace(const WORKSPACEID&, const std::string& name = "");
void setActiveMonitor(CMonitor*);
bool isWorkspaceSpecial(const int&);
int getNewSpecialID();
bool isWorkspaceSpecial(const WORKSPACEID&);
WORKSPACEID getNewSpecialID();
void performUserChecks();
void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace);
PHLWINDOW getForceFocus();
@@ -177,6 +182,7 @@ class CCompositor {
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates();
PHLWINDOW windowForCPointer(CWindow*);
void onNewMonitor(SP<Aquamarine::IOutput> output);
std::string explicitConfigPath;
@@ -190,6 +196,7 @@ class CCompositor {
uint64_t m_iHyprlandPID = 0;
wl_event_source* m_critSigSource = nullptr;
rlimit m_sOriginalNofile = {0};
};
inline std::unique_ptr<CCompositor> g_pCompositor;

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
#include "../debug/Log.hpp"
#include <unordered_map>
#include "../defines.hpp"
#include <variant>
#include <vector>
#include <deque>
#include <algorithm>
@@ -15,7 +16,7 @@
#include <xf86drmMode.h>
#include "../helpers/WLClasses.hpp"
#include "../helpers/Monitor.hpp"
#include "../helpers/VarList.hpp"
#include "../helpers/varlist/VarList.hpp"
#include "../desktop/Window.hpp"
#include "../desktop/LayerSurface.hpp"
@@ -33,16 +34,16 @@ struct SWorkspaceRule {
std::string monitor = "";
std::string workspaceString = "";
std::string workspaceName = "";
int workspaceId = -1;
WORKSPACEID workspaceId = -1;
bool isDefault = false;
bool isPersistent = false;
std::optional<CCssGapData> gapsIn;
std::optional<CCssGapData> gapsOut;
std::optional<int64_t> borderSize;
std::optional<int> border;
std::optional<int> rounding;
std::optional<int> decorate;
std::optional<int> shadow;
std::optional<bool> decorate;
std::optional<bool> noRounding;
std::optional<bool> noBorder;
std::optional<bool> noShadow;
std::optional<std::string> onCreatedEmptyRunCmd;
std::optional<std::string> defaultName;
std::map<std::string, std::string> layoutopts;
@@ -83,6 +84,70 @@ struct SExecRequestedRule {
uint64_t iPid = 0;
};
enum eConfigOptionType : uint16_t {
CONFIG_OPTION_BOOL = 0,
CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/
CONFIG_OPTION_FLOAT = 2,
CONFIG_OPTION_STRING_SHORT = 3, /* e.g. "auto" */
CONFIG_OPTION_STRING_LONG = 4, /* e.g. a command */
CONFIG_OPTION_COLOR = 5,
CONFIG_OPTION_CHOICE = 6, /* e.g. "one", "two", "three" */
CONFIG_OPTION_GRADIENT = 7,
CONFIG_OPTION_VECTOR = 8,
};
enum eConfigOptionFlags : uint32_t {
CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0),
};
struct SConfigOptionDescription {
struct SBoolData {
bool value = false;
};
struct SRangeData {
int value = 0, min = 0, max = 2;
};
struct SFloatData {
float value = 0, min = 0, max = 100;
};
struct SStringData {
std::string value;
};
struct SColorData {
CColor color;
};
struct SChoiceData {
int firstIndex = 0;
std::string choices; // comma-separated
};
struct SGradientData {
std::string gradient;
};
struct SVectorData {
Vector2D vec, min, max;
};
std::string value; // e.g. general:gaps_in
std::string description;
std::string specialCategory; // if value is special (e.g. device:abc) value will be abc and special device
bool specialKey = false;
eConfigOptionType type = CONFIG_OPTION_BOOL;
uint32_t flags = 0; // eConfigOptionFlags
std::string jsonify() const;
//
std::variant<SBoolData, SRangeData, SFloatData, SStringData, SColorData, SChoiceData, SGradientData, SVectorData> data;
};
class CConfigManager {
public:
CConfigManager();
@@ -101,11 +166,10 @@ class CConfigManager {
void* const* getConfigValuePtr(const std::string&);
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load);
static std::string getConfigDir();
static std::string getMainConfigPath();
const std::string getConfigString();
SMonitorRule getMonitorRuleFor(const CMonitor&);
SMonitorRule getMonitorRuleFor(const SP<CMonitor>);
SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
std::string getDefaultWorkspaceFor(const std::string&);
@@ -116,6 +180,8 @@ class CConfigManager {
std::vector<SWindowRule> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false);
std::vector<SLayerRule> getMatchingRules(PHLLS);
const std::vector<SConfigOptionDescription>& getAllDescriptions();
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
@@ -126,13 +192,11 @@ class CConfigManager {
// no-op when done.
void dispatchExecOnce();
void dispatchExecShutdown();
void performMonitorReload();
void appendMonitorRule(const SMonitorRule&);
bool replaceMonitorRule(const SMonitorRule&);
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
void ensureMonitorStatus();
void ensureVRR(CMonitor* pMonitor = nullptr);
@@ -150,6 +214,7 @@ class CConfigManager {
// keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleExecShutdown(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
@@ -168,6 +233,37 @@ class CConfigManager {
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:
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
@@ -195,6 +291,7 @@ class CConfigManager {
bool firstExecDispatched = false;
bool m_bManualCrashInitiated = false;
std::deque<std::string> firstExecRequests;
std::deque<std::string> finalExecRequests;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_szConfigErrors = "";
@@ -204,7 +301,8 @@ class CConfigManager {
void updateBlurredLS(const std::string&, const bool);
void setDefaultAnimationVars();
std::optional<std::string> resetHLConfig();
std::optional<std::string> verifyConfigExists();
static std::optional<std::string> generateConfig(std::string configPath);
static std::optional<std::string> verifyConfigExists();
void postConfigReload(const Hyprlang::CParseResult& result);
void reload();
SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&);

View File

@@ -11,7 +11,7 @@ template <typename T>
class CConfigValue {
public:
CConfigValue(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val.c_str());
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val);
p_ = PVHYPRLANG->getDataStaticPtr();

View File

@@ -138,7 +138,7 @@ dwindle {
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
master {
new_is_master = true
new_status = master
}
# https://wiki.hyprland.org/Configuring/Variables/#misc
@@ -182,9 +182,9 @@ device {
}
####################
### KEYBINDINGSS ###
####################
###################
### KEYBINDINGS ###
###################
# See https://wiki.hyprland.org/Configuring/Keywords/
$mainMod = SUPER # Sets "Windows" key as main modifier
@@ -241,6 +241,19 @@ bind = $mainMod, mouse_up, workspace, e-1
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
# Laptop multimedia keys for volume and LCD brightness
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+
bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%-
# Requires playerctl
bindl = , XF86AudioNext, exec, playerctl next
bindl = , XF86AudioPause, exec, playerctl play-pause
bindl = , XF86AudioPlay, exec, playerctl play-pause
bindl = , XF86AudioPrev, exec, playerctl previous
##############################
### WINDOWS AND WORKSPACES ###
@@ -255,5 +268,9 @@ bindm = $mainMod, mouse:273, resizewindow
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
# Ignore maximize requests from apps. You'll probably like this.
windowrulev2 = suppressevent maximize, class:.*
# Fix some dragging issues with XWayland
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
)#";

View File

@@ -5,6 +5,7 @@
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <filesystem>
#include "../plugins/PluginSystem.hpp"
#include "../signal-safe.hpp"
@@ -85,7 +86,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
stderr.flush();
}
reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRWXU);
reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (reportFd < 0) {
exit_with_error("Failed to open crash report path for writing");
}
@@ -104,7 +105,19 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += GIT_COMMIT_HASH;
finalCrashReport += "\nTag: ";
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) {
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,9 @@
#include "../helpers/MiscFunctions.hpp"
#include <functional>
// exposed for main.cpp
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request);
class CHyprCtl {
public:
CHyprCtl();
@@ -22,11 +25,16 @@ class CHyprCtl {
bool sysInfoConfig = false;
} 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:
void startHyprCtlSocket();
std::vector<SP<SHyprCtlCommand>> m_vCommands;
wl_event_source* m_eventSource = nullptr;
std::string m_socketPath;
};
inline std::unique_ptr<CHyprCtl> g_pHyprCtl;

View File

@@ -7,8 +7,8 @@ CHyprDebugOverlay::CHyprDebugOverlay() {
m_pTexture = makeShared<CTexture>();
}
void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
m_dLastRenderTimes.push_back(µs / 1000.f);
void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
m_dLastRenderTimes.push_back(durationUs / 1000.f);
if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimes.pop_front();
@@ -17,8 +17,8 @@ void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
m_pMonitor = pMonitor;
}
void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) {
m_dLastRenderTimesNoOverlay.push_back(µs / 1000.f);
void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f);
if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate)
m_dLastRenderTimesNoOverlay.pop_front();
@@ -57,7 +57,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float avgFrametime = 0;
float maxFrametime = 0;
float minFrametime = 9999;
for (auto& ft : m_dLastFrametimes) {
for (auto const& ft : m_dLastFrametimes) {
if (ft > maxFrametime)
maxFrametime = ft;
if (ft < minFrametime)
@@ -70,7 +70,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float avgRenderTime = 0;
float maxRenderTime = 0;
float minRenderTime = 9999;
for (auto& rt : m_dLastRenderTimes) {
for (auto const& rt : m_dLastRenderTimes) {
if (rt > maxRenderTime)
maxRenderTime = rt;
if (rt < minRenderTime)
@@ -83,7 +83,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float avgRenderTimeNoOverlay = 0;
float maxRenderTimeNoOverlay = 0;
float minRenderTimeNoOverlay = 9999;
for (auto& rt : m_dLastRenderTimesNoOverlay) {
for (auto const& rt : m_dLastRenderTimesNoOverlay) {
if (rt > maxRenderTimeNoOverlay)
maxRenderTimeNoOverlay = rt;
if (rt < minRenderTimeNoOverlay)
@@ -96,7 +96,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
float avgAnimMgrTick = 0;
float maxAnimMgrTick = 0;
float minAnimMgrTick = 9999;
for (auto& at : m_dLastAnimationTicks) {
for (auto const& at : m_dLastAnimationTicks) {
if (at > maxAnimMgrTick)
maxAnimMgrTick = at;
if (at < minAnimMgrTick)
@@ -188,12 +188,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) {
return posY - offset;
}
void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) {
m_mMonitorOverlays[pMonitor].renderData(pMonitor, µs);
void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) {
m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs);
}
void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) {
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, µs);
void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) {
m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs);
}
void CHyprDebugOverlay::frameData(CMonitor* pMonitor) {
@@ -217,7 +217,7 @@ void CHyprDebugOverlay::draw() {
// draw the things
int offsetY = 0;
for (auto& m : g_pCompositor->m_vMonitors) {
for (auto const& m : g_pCompositor->m_vMonitors) {
offsetY += m_mMonitorOverlays[m.get()].draw(offsetY);
offsetY += 5; // for padding between mons
}

View File

@@ -13,8 +13,8 @@ class CHyprMonitorDebugOverlay {
public:
int draw(int offset);
void renderData(CMonitor* pMonitor, float µs);
void renderDataNoOverlay(CMonitor* pMonitor, float µs);
void renderData(CMonitor* pMonitor, float durationUs);
void renderDataNoOverlay(CMonitor* pMonitor, float durationUs);
void frameData(CMonitor* pMonitor);
private:
@@ -33,8 +33,8 @@ class CHyprDebugOverlay {
public:
CHyprDebugOverlay();
void draw();
void renderData(CMonitor*, float µs);
void renderDataNoOverlay(CMonitor*, float µs);
void renderData(CMonitor*, float durationUs);
void renderDataNoOverlay(CMonitor*, float durationUs);
void frameData(CMonitor*);
private:

View File

@@ -44,7 +44,7 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC
PNOTIF->icon = icon;
PNOTIF->fontSize = fontSize;
for (auto& m : g_pCompositor->m_vMonitors) {
for (auto const& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m.get());
}
}
@@ -87,7 +87,7 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
const auto iconBackendID = iconBackendFromLayout(layout);
const auto PBEZIER = g_pAnimationManager->getBezier("default");
for (auto& notif : m_dNotifications) {
for (auto const& notif : m_dNotifications) {
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
@@ -131,7 +131,7 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
textW /= 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
cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a);

View File

@@ -1,36 +1,21 @@
#include "Log.hpp"
#include "../defines.hpp"
#include "../Compositor.hpp"
#include "RollingLogFollow.hpp"
#include <fstream>
#include <iostream>
#include <fcntl.h>
void Debug::init(const std::string& IS) {
logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
logOfs.open(logFile, std::ios::out | std::ios::app);
auto handle = logOfs.native_handle();
fcntl(handle, F_SETFD, FD_CLOEXEC);
}
void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
if (level > wlr_log_get_verbosity())
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::close() {
logOfs.close();
}
void Debug::log(LogLevel level, std::string str) {
@@ -73,13 +58,13 @@ void Debug::log(LogLevel level, std::string str) {
if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
if (RollingLogFollow::Get().IsRunning())
RollingLogFollow::Get().AddLog(str);
if (!disableLogs || !**disableLogs) {
// log to a file
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
ofs << str << "\n";
ofs.close();
logOfs << str << "\n";
logOfs.flush();
}
// log it to the stdout too.

View File

@@ -4,6 +4,7 @@
#include <iostream>
#include <fstream>
#include <chrono>
#include <mutex>
#include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp"
@@ -22,6 +23,7 @@ enum LogLevel {
namespace Debug {
inline std::string logFile;
inline std::ofstream logOfs;
inline int64_t* const* disableLogs = nullptr;
inline int64_t* const* disableTime = nullptr;
inline bool disableStdout = false;
@@ -30,14 +32,18 @@ namespace Debug {
inline int64_t* const* coloredLogs = nullptr;
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 close();
//
void log(LogLevel level, std::string str);
template <typename... Args>
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
std::lock_guard<std::mutex> guard(logMutex);
if (level == TRACE && !trace)
return;
@@ -49,7 +55,8 @@ namespace Debug {
// print date and time to the ofs
if (disableTime && !**disableTime) {
#ifndef _LIBCPP_VERSION
const auto zt = std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::system_clock::now()};
static auto current_zone = std::chrono::current_zone();
const auto zt = std::chrono::zoned_time{current_zone, std::chrono::system_clock::now()};
const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor<std::chrono::days>(zt.get_local_time())};
#else
// TODO: current clang 17 does not support `zoned_time`, remove this once clang 19 is ready
@@ -67,6 +74,4 @@ namespace Debug {
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

@@ -1,6 +1,5 @@
#include "includes.hpp"
#include "debug/Log.hpp"
#include "helpers/WLListener.hpp"
#include "helpers/Color.hpp"
#include "macros.hpp"
#include "desktop/DesktopTypes.hpp"

View File

@@ -71,10 +71,16 @@ CLayerSurface::~CLayerSurface() {
surface->unassign();
g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); });
for (auto const& mon : g_pCompositor->m_vRealMonitors) {
for (auto& lsl : mon->m_aLayerSurfaceLayers) {
std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; });
}
}
}
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);
@@ -111,13 +117,24 @@ void CLayerSurface::onDestroy() {
layerSurface.reset();
if (surface)
surface->unassign();
listeners.unmap.reset();
listeners.destroy.reset();
listeners.map.reset();
listeners.commit.reset();
}
void CLayerSurface::onMap() {
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface);
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface.get());
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
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
@@ -133,12 +150,15 @@ void CLayerSurface::onMap() {
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);
const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
const bool GRABSFOCUS = ISEXCLUSIVE ||
(layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained
(g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained());
(g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()));
if (GRABSFOCUS) {
// TODO: use the new superb really very cool grab
@@ -156,7 +176,7 @@ void CLayerSurface::onMap() {
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
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));
readyToDelete = false;
@@ -170,22 +190,21 @@ void CLayerSurface::onMap() {
}
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});
EMIT_HOOK_EVENT("closeLayer", 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) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
g_pCompositor->addToFadingOutSafe(self.lock());
mapped = false;
if (layerSurface && layerSurface->surface)
layerSurface->surface->unmap();
startAnimation(false);
return;
@@ -197,6 +216,8 @@ void CLayerSurface::onUnmap() {
startAnimation(false);
mapped = false;
if (layerSurface && layerSurface->surface)
layerSurface->surface->unmap();
g_pCompositor->addToFadingOutSafe(self.lock());
@@ -204,39 +225,15 @@ void CLayerSurface::onUnmap() {
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
surface.reset();
if (!PMONITOR)
return;
// refocus if needed
if (WASLASTFOCUS) {
g_pInputManager->releaseAllMouseButtons();
Vector2D surfaceCoords;
PHLLS pFoundLayerSurface;
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();
}
}
// vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable()))
g_pInputManager->refocusLastWindow(PMONITOR);
else if (g_pCompositor->m_pLastFocus)
g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock());
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
g_pHyprRenderer->damageBox(&geomFixed);
@@ -246,12 +243,25 @@ void CLayerSurface::onUnmap() {
g_pHyprRenderer->damageBox(&geomFixed);
g_pInputManager->sendMotionEventsToFocused();
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
}
void CLayerSurface::onCommit() {
if (!layerSurface)
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);
if (!PMONITOR)
@@ -311,18 +321,35 @@ void CLayerSurface::onCommit() {
realSize.setValueAndWarp(geometry.size());
}
if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained
&& !keyboardExclusive && mapped) {
if (mapped) {
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == 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;
if (!WASEXCLUSIVE && ISEXCLUSIVE)
g_pInputManager->m_dExclusiveLSes.push_back(self);
else if (WASEXCLUSIVE && !ISEXCLUSIVE)
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
// 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;
} else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) {
g_pInputManager->refocus();
}
}
keyboardExclusive = layerSurface->current.interactivity;
interactivity = layerSurface->current.interactivity;
g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y);
@@ -339,7 +366,7 @@ void CLayerSurface::applyRules() {
xray = -1;
animationStyle.reset();
for (auto& rule : g_pConfigManager->getMatchingRules(self.lock())) {
for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) {
if (rule.rule == "noanim")
noAnimations = true;
else if (rule.rule == "blur")
@@ -367,6 +394,11 @@ void CLayerSurface::applyRules() {
} else if (rule.rule.starts_with("animation")) {
CVarList vars{rule.rule, 2, 's'};
animationStyle = vars[1];
} else if (rule.rule.starts_with("order")) {
CVarList vars{rule.rule, 2, 's'};
try {
order = std::stoi(vars[1]);
} catch (...) { Debug::log(ERR, "Invalid value passed to order"); }
}
}
}
@@ -405,9 +437,9 @@ void CLayerSurface::startAnimation(bool in, bool instant) {
}
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{0, PMONITOR->vecSize.y},
PMONITOR->vecPosition + Vector2D{0.0, PMONITOR->vecSize.y},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2},
};

View File

@@ -34,14 +34,15 @@ class CLayerSurface {
WP<CLayerShellResource> layerSurface;
wl_list link;
bool keyboardExclusive = false;
// the header providing the enum type cannot be imported here
int interactivity = 0;
SP<CWLSurface> surface;
bool mapped = false;
uint32_t layer = 0;
int monitorID = -1;
MONITORID monitorID = -1;
bool fadingOut = false;
bool readyToDelete = false;
@@ -50,10 +51,11 @@ class CLayerSurface {
bool forceBlur = false;
bool forceBlurPopups = false;
int xray = -1;
int64_t xray = -1;
bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f;
bool dimAround = false;
int64_t order = 0;
std::optional<std::string> animationStyle;

View File

@@ -22,7 +22,7 @@ CPopup::CPopup(SP<CXDGPopupResource> popup, CPopup* pOwner) : m_pParent(pOwner),
m_pWindowOwner = pOwner->m_pWindowOwner;
m_vLastSize = popup->surface->current.geometry.size();
unconstrain();
reposition();
initAllSignals();
}
@@ -55,7 +55,7 @@ void CPopup::initAllSignals() {
}
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);
}
@@ -188,18 +188,25 @@ void CPopup::onReposition() {
m_vLastPos = coordsRelativeToParent();
unconstrain();
reposition();
}
void CPopup::unconstrain() {
void CPopup::reposition() {
const auto COORDS = t1ParentCoords();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
if (!PMONITOR)
return;
CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
m_pResource->applyPositioning(box, COORDS - PMONITOR->vecPosition);
CBox box = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
m_pResource->applyPositioning(box, COORDS);
}
SP<CWLSurface> CPopup::getT1Owner() {
if (m_pWindowOwner)
return m_pWindowOwner->m_pWLSurface;
else
return m_pLayerOwner->surface;
}
Vector2D CPopup::coordsRelativeToParent() {
@@ -250,7 +257,8 @@ void CPopup::recheckTree() {
}
void CPopup::recheckChildrenRecursive() {
for (auto& c : m_vChildren) {
auto cpy = m_vChildren;
for (auto const& c : cpy) {
c->onCommit(true);
c->recheckChildrenRecursive();
}
@@ -281,14 +289,14 @@ bool CPopup::visible() {
}
void CPopup::bfHelper(std::vector<CPopup*> nodes, std::function<void(CPopup*, void*)> fn, void* data) {
for (auto& n : nodes) {
for (auto const& n : nodes) {
fn(n, data);
}
std::vector<CPopup*> nodes2;
for (auto& n : nodes) {
for (auto& c : n->m_vChildren) {
for (auto const& n : nodes) {
for (auto const& c : n->m_vChildren) {
nodes2.push_back(c.get());
}
}
@@ -307,7 +315,7 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
std::vector<CPopup*> popups;
breadthfirst([](CPopup* popup, void* data) { ((std::vector<CPopup*>*)data)->push_back(popup); }, &popups);
for (auto& p : popups | std::views::reverse) {
for (auto const& p : popups | std::views::reverse) {
if (!p->m_pResource)
continue;

View File

@@ -3,7 +3,7 @@
#include <vector>
#include <memory>
#include "Subsurface.hpp"
#include "../helpers/signal/Listener.hpp"
#include "../helpers/signal/Signal.hpp"
class CXDGPopupResource;
@@ -18,6 +18,7 @@ class CPopup {
~CPopup();
SP<CWLSurface> getT1Owner();
Vector2D coordsRelativeToParent();
Vector2D coordsGlobal();
@@ -60,7 +61,7 @@ class CPopup {
bool m_bMapped = false;
//
std::vector<std::unique_ptr<CPopup>> m_vChildren;
std::vector<SP<CPopup>> m_vChildren;
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
struct {
@@ -74,7 +75,7 @@ class CPopup {
} listeners;
void initAllSignals();
void unconstrain();
void reposition();
void recheckChildrenRecursive();
void sendScale();

View File

@@ -30,13 +30,7 @@ CSubsurface::CSubsurface(SP<CWLSubsurfaceResource> pSubsurface, CPopup* pOwner)
}
CSubsurface::~CSubsurface() {
hyprListener_newSubsurface.removeCallback();
if (!m_pSubsurface)
return;
hyprListener_commitSubsurface.removeCallback();
hyprListener_destroySubsurface.removeCallback();
;
}
void CSubsurface::initSignals() {
@@ -65,7 +59,7 @@ void CSubsurface::checkSiblingDamage() {
const double SCALE = m_pWindowParent.lock() && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0;
for (auto& n : m_pParent->m_vChildren) {
for (auto const& n : m_pParent->m_vChildren) {
if (n.get() == this)
continue;
@@ -75,7 +69,7 @@ void CSubsurface::checkSiblingDamage() {
}
void CSubsurface::recheckDamageForSubsurfaces() {
for (auto& n : m_vChildren) {
for (auto const& n : m_vChildren) {
const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y);
}
@@ -183,7 +177,7 @@ Vector2D CSubsurface::coordsGlobal() {
}
void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) {
for (auto& s : pSurface->subsurfaces) {
for (auto const& s : pSurface->subsurfaces) {
if (!s || s->surface->hlSurface /* already assigned */)
continue;
onNewSubsurface(s.lock());

View File

@@ -35,10 +35,6 @@ class CSubsurface {
void recheckDamageForSubsurfaces();
private:
DYNLISTENER(destroySubsurface);
DYNLISTENER(commitSubsurface);
DYNLISTENER(newSubsurface);
struct {
CHyprSignalListener destroySubsurface;
CHyprSignalListener commitSubsurface;

View File

@@ -1,6 +1,7 @@
#include "WLSurface.hpp"
#include "../Compositor.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../protocols/LayerShell.hpp"
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_pResource = pSurface;
@@ -56,12 +57,12 @@ bool CWLSurface::small() const {
if (!validMapped(m_pWindowOwner) || !exists())
return false;
if (!m_pResource->current.buffer)
if (!m_pResource->current.texture)
return false;
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.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1;
}
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);
}
Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists() || !m_pResource->current.buffer)
Vector2D CWLSurface::correctSmallVecBuf() const {
if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.texture)
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 {
if (!m_pResource->current.buffer)
Vector2D CWLSurface::getViewporterCorrectedSize() const {
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 {};
CRegion damage = m_pResource->accumulateCurrentBufferDamage();
damage.transform(m_pResource->current.transform, m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y);
damage.scale(1.0 / m_pResource->current.scale);
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y);
const auto VPSIZE = getViewporterCorrectedSize();
const auto CORRECTVEC = correctSmallVec();
const auto BUFSIZE = m_pResource->current.bufferSize;
const auto CORRECTVEC = correctSmallVecBuf();
if (m_pResource->current.viewport.hasSource)
damage.intersect(m_pResource->current.viewport.source);
const auto SCALEDSRCSIZE =
m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size;
const auto SCALEDSRCSIZE = m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.bufferSize;
damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y});
damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y});
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;
}
@@ -141,27 +161,27 @@ void CWLSurface::init() {
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
}
PHLWINDOW CWLSurface::getWindow() {
PHLWINDOW CWLSurface::getWindow() const {
return m_pWindowOwner.lock();
}
PHLLS CWLSurface::getLayer() {
PHLLS CWLSurface::getLayer() const {
return m_pLayerOwner.lock();
}
CPopup* CWLSurface::getPopup() {
CPopup* CWLSurface::getPopup() const {
return m_pPopupOwner;
}
CSubsurface* CWLSurface::getSubsurface() {
CSubsurface* CWLSurface::getSubsurface() const {
return m_pSubsurfaceOwner;
}
bool CWLSurface::desktopComponent() {
bool CWLSurface::desktopComponent() const {
return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner;
}
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() {
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const {
if (!desktopComponent())
return {};
@@ -181,7 +201,7 @@ void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) {
m_pConstraint = constraint;
}
SP<CPointerConstraint> CWLSurface::constraint() {
SP<CPointerConstraint> CWLSurface::constraint() const {
return m_pConstraint.lock();
}
@@ -202,3 +222,11 @@ SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
return nullptr;
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
#include "../defines.hpp"
#include "../helpers/Region.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/signal/Signal.hpp"
class CSubsurface;
@@ -35,20 +35,22 @@ class CWLSurface {
bool exists() const;
bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D correctSmallVecBuf() const; // returns a corrective vector for small() surfaces, in BL coords
Vector2D getViewporterCorrectedSize() const;
CRegion logicalDamage() const;
CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned
bool visible();
bool keyboardFocusable() const;
// getters for owners.
PHLWINDOW getWindow();
PHLLS getLayer();
CPopup* getPopup();
CSubsurface* getSubsurface();
PHLWINDOW getWindow() const;
PHLLS getLayer() const;
CPopup* getPopup() const;
CSubsurface* getSubsurface() const;
// desktop components misc utils
std::optional<CBox> getSurfaceBoxGlobal();
std::optional<CBox> getSurfaceBoxGlobal() const;
void appendConstraint(WP<CPointerConstraint> constraint);
SP<CPointerConstraint> constraint();
SP<CPointerConstraint> constraint() const;
// allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false;
@@ -107,7 +109,7 @@ class CWLSurface {
void destroy();
void init();
bool desktopComponent();
bool desktopComponent() const;
struct {
CHyprSignalListener destroy;

View File

@@ -1,4 +1,5 @@
#include <any>
#include <bit>
#include <string_view>
#include <algorithm>
#include "Window.hpp"
@@ -12,12 +13,14 @@
#include "../protocols/core/Compositor.hpp"
#include "../xwayland/XWayland.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
pWindow->m_pSelf = pWindow;
pWindow->m_bIsX11 = true;
pWindow->m_iX11Type = surface->overrideRedirect ? 2 : 1;
pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE);
@@ -27,6 +30,7 @@ PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
@@ -48,6 +52,7 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW);
pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE);
pWindow->addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(pWindow));
pWindow->addWindowDeco(std::make_unique<CHyprBorderDecoration>(pWindow));
@@ -101,19 +106,19 @@ CWindow::~CWindow() {
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)
return m_eOriginalClosedExtents;
const int BORDERSIZE = getRealBorderSize();
if (m_sAdditionalConfigData.dimAround) {
if (m_sWindowData.dimAround.valueOrDefault()) {
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},
{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());
@@ -167,7 +172,7 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
}
CBox CWindow::getFullWindowBoundingBox() {
if (m_sAdditionalConfigData.dimAround) {
if (m_sWindowData.dimAround.valueOrDefault()) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR)
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
}
@@ -189,7 +194,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
auto POS = m_vPosition;
auto SIZE = m_vSize;
if (m_bIsFullscreen) {
if (isFullscreen()) {
POS = PMONITOR->vecPosition;
SIZE = PMONITOR->vecSize;
@@ -215,13 +220,13 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
}
CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (m_sAdditionalConfigData.dimAround) {
if (m_sWindowData.dimAround.valueOrDefault()) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR)
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)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock()));
if (properties & INPUT_EXTENTS)
@@ -239,7 +244,7 @@ CBox CWindow::getWindowMainSurfaceBox() {
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());
}
@@ -248,7 +253,7 @@ void CWindow::updateWindowDecos() {
if (!m_bIsMapped || isHidden())
return;
for (auto& wd : m_vDecosToRemove) {
for (auto const& wd : m_vDecosToRemove) {
for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) {
if (it->get() == wd) {
g_pDecorationPositioner->uncacheDecoration(it->get());
@@ -266,11 +271,11 @@ void CWindow::updateWindowDecos() {
// make a copy because updateWindow can remove decos.
std::vector<IHyprWindowDecoration*> decos;
for (auto& wd : m_dWindowDecorations) {
for (auto const& wd : m_dWindowDecorations) {
decos.push_back(wd.get());
}
for (auto& wd : decos) {
for (auto const& wd : decos) {
if (std::find_if(m_dWindowDecorations.begin(), m_dWindowDecorations.end(), [wd](const auto& other) { return other.get() == wd; }) == m_dWindowDecorations.end())
continue;
wd->updateWindow(m_pSelf.lock());
@@ -292,7 +297,7 @@ void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
}
void CWindow::uncacheWindowDecos() {
for (auto& wd : m_dWindowDecorations) {
for (auto const& wd : m_dWindowDecorations) {
g_pDecorationPositioner->uncacheDecoration(wd.get());
}
}
@@ -301,7 +306,7 @@ bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoor
if (type != INPUT_TYPE_DRAG_END && hasPopupAt(mouseCoords))
return false;
for (auto& wd : m_dWindowDecorations) {
for (auto const& wd : m_dWindowDecorations) {
if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))
continue;
@@ -333,7 +338,7 @@ pid_t CWindow::getPID() {
}
IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) {
for (auto& wd : m_dWindowDecorations) {
for (auto const& wd : m_dWindowDecorations) {
if (wd->getDecorationType() == type)
return wd.get();
}
@@ -403,16 +408,21 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
const auto OLDWORKSPACE = m_pWorkspace;
m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->m_iMonitorID : -1;
m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F);
m_fMovingToWorkspaceAlpha = 0.F;
m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; });
m_pWorkspace = pWorkspace;
setAnimationsToMove();
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_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -442,13 +452,15 @@ PHLWINDOW CWindow::X11TransientFor() {
return nullptr;
auto s = m_pXWaylandSurface->parent;
auto oldParent = 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;
s = s->parent;
}
for (auto& w : g_pCompositor->m_vWindows) {
for (auto const& w : g_pCompositor->m_vWindows) {
if (w->m_pXWaylandSurface != s)
continue;
return w;
@@ -458,7 +470,7 @@ PHLWINDOW CWindow::X11TransientFor() {
}
void CWindow::removeDecorationByType(eDecorationType type) {
for (auto& wd : m_dWindowDecorations) {
for (auto const& wd : m_dWindowDecorations) {
if (wd->getDecorationType() == type)
m_vDecosToRemove.push_back(wd.get());
}
@@ -472,12 +484,6 @@ void unregisterVar(void* ptr) {
void CWindow::onUnmap() {
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
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()) {
@@ -502,6 +508,7 @@ void CWindow::onUnmap() {
m_fAlpha.setCallbackOnEnd(unregisterVar);
m_cRealShadowColor.setCallbackOnEnd(unregisterVar);
m_fDimPercent.setCallbackOnEnd(unregisterVar);
m_fMovingToWorkspaceAlpha.setCallbackOnEnd(unregisterVar);
m_vRealSize.setCallbackOnBegin(nullptr);
@@ -519,7 +526,7 @@ void CWindow::onUnmap() {
PMONITOR->solitaryClient.reset();
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -542,6 +549,7 @@ void CWindow::onMap() {
m_fAlpha.resetAllCallbacks();
m_cRealShadowColor.resetAllCallbacks();
m_fDimPercent.resetAllCallbacks();
m_fMovingToWorkspaceAlpha.resetAllCallbacks();
m_vRealPosition.registerVar();
m_vRealSize.registerVar();
@@ -551,6 +559,7 @@ void CWindow::onMap() {
m_fAlpha.registerVar();
m_cRealShadowColor.registerVar();
m_fDimPercent.registerVar();
m_fMovingToWorkspaceAlpha.registerVar();
m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false);
@@ -602,65 +611,39 @@ bool CWindow::isHidden() {
}
void CWindow::applyDynamicRule(const SWindowRule& r) {
if (r.szRule == "noblur") {
m_sAdditionalConfigData.forceNoBlur = true;
} else if (r.szRule == "noborder") {
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")) {
const eOverridePriority priority = r.szValue == "execRule" ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE;
const CVarList VARS(r.szRule, 0, ' ');
if (r.szRule.starts_with("tag")) {
CVarList vars{r.szRule, 0, 's', true};
if (vars.size() == 2 && vars[0] == "tag")
m_tags.applyTag(vars[1], true);
else
Debug::log(ERR, "Tag rule invalid: {}", r.szRule);
} else if (r.szRule.starts_with("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")) {
try {
CVarList vars(r.szRule, 0, ' ');
int opacityIDX = 0;
for (auto& r : vars) {
for (auto const& r : vars) {
if (r == "opacity")
continue;
if (r == "override") {
if (opacityIDX == 1)
m_sSpecialRenderData.alphaOverride = true;
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority);
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)
m_sSpecialRenderData.alphaFullscreenOverride = true;
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority);
} else {
if (opacityIDX == 0) {
m_sSpecialRenderData.alpha = std::stof(r);
m_sSpecialRenderData.alphaOverride = false;
m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 1) {
m_sSpecialRenderData.alphaInactive = std::stof(r);
m_sSpecialRenderData.alphaInactiveOverride = false;
m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else if (opacityIDX == 2) {
m_sSpecialRenderData.alphaFullscreen = std::stof(r);
m_sSpecialRenderData.alphaFullscreenOverride = false;
m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority);
} else {
throw std::runtime_error("more than 3 alpha values");
}
@@ -670,33 +653,29 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
}
if (opacityIDX == 1) {
m_sSpecialRenderData.alphaInactiveOverride = m_sSpecialRenderData.alphaOverride;
m_sSpecialRenderData.alphaInactive = m_sSpecialRenderData.alpha;
m_sSpecialRenderData.alphaFullscreenOverride = m_sSpecialRenderData.alphaOverride;
m_sSpecialRenderData.alphaFullscreen = m_sSpecialRenderData.alpha;
m_sWindowData.alphaInactive = m_sWindowData.alpha;
m_sWindowData.alphaFullscreen = m_sWindowData.alpha;
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "noanim") {
m_sAdditionalConfigData.forceNoAnims = true;
} else if (r.szRule.starts_with("animation")) {
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")) {
try {
// Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = {};
CGradientValueData inactiveBorderGradient = {};
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
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0])));
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1])));
m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))), priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))), priority);
return;
}
for (auto& token : colorsAndAngles) {
for (auto const& token : colorsAndAngles) {
// The first angle, or an explicit "0deg", splits the two gradients
if (active && token.contains("deg")) {
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
@@ -715,24 +694,24 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
else if (activeBorderGradient.m_vColors.empty())
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
else if (inactiveBorderGradient.m_vColors.empty())
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
else {
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient;
m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority);
m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority);
}
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "dimaround") {
m_sAdditionalConfigData.dimAround = true;
} else if (r.szRule == "keepaspectratio") {
m_sAdditionalConfigData.keepAspectRatio = true;
} else if (r.szRule.starts_with("focusonactivate")) {
m_sAdditionalConfigData.focusOnActivate = true;
} else if (r.szRule.starts_with("xray")) {
CVarList vars(r.szRule, 0, ' ');
} else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[0]); search != g_pConfigManager->mbWindowProperties.end()) {
if (VARS[1].empty()) {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority);
} else {
try {
m_sAdditionalConfigData.xray = configStringToInt(vars[1]);
*(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]), priority);
} catch (...) {}
}
} else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) {
try {
*(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[1]), priority);
} catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("idleinhibit")) {
auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
@@ -756,9 +735,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
return;
}
m_sAdditionalConfigData.maxSize = VEC;
m_vRealSize = Vector2D(std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().x, m_vRealSize.goal().x),
std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().y, m_vRealSize.goal().y));
m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority);
m_vRealSize =
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());
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("minsize")) {
@@ -771,46 +750,41 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
return;
}
m_sAdditionalConfigData.minSize = VEC;
m_vRealSize = Vector2D(std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().x, m_vRealSize.goal().x),
std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().y, m_vRealSize.goal().y));
m_sWindowData.minSize = CWindowOverridableVar(VEC, priority);
m_vRealSize =
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());
if (m_sGroupData.pNextWindow.expired())
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "renderunfocused") {
m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority);
g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock());
}
}
void CWindow::updateDynamicRules() {
m_sSpecialRenderData.activeBorderColor = CGradientValueData();
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData();
m_sSpecialRenderData.alpha = 1.f;
m_sSpecialRenderData.alphaInactive = -1.f;
m_sAdditionalConfigData.forceNoBlur = false;
m_sAdditionalConfigData.forceNoBorder = false;
m_sAdditionalConfigData.forceNoShadow = false;
m_sAdditionalConfigData.forceNoDim = false;
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = false;
m_sAdditionalConfigData.maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
m_sAdditionalConfigData.minSize = Vector2D(20, 20);
m_sAdditionalConfigData.forceNoAnims = false;
m_sAdditionalConfigData.animationStyle = std::string("");
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_sWindowData.alpha.unset(PRIORITY_WINDOW_RULE);
m_sWindowData.alphaInactive.unset(PRIORITY_WINDOW_RULE);
m_sWindowData.alphaFullscreen.unset(PRIORITY_WINDOW_RULE);
unsetWindowData(PRIORITY_WINDOW_RULE);
m_sWindowData.animationStyle.unset(PRIORITY_WINDOW_RULE);
m_sWindowData.maxSize.unset(PRIORITY_WINDOW_RULE);
m_sWindowData.minSize.unset(PRIORITY_WINDOW_RULE);
m_sWindowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE);
m_sWindowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE);
m_sWindowData.renderUnfocused.unset(PRIORITY_WINDOW_RULE);
m_eIdleInhibitMode = IDLEINHIBIT_NONE;
m_tags.removeDynamicTags();
m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock());
for (auto& r : m_vMatchedRules) {
for (auto const& r : m_vMatchedRules) {
applyDynamicRule(r);
}
@@ -882,7 +856,7 @@ void CWindow::createGroup() {
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(m_pSelf.lock()));
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -900,7 +874,7 @@ void CWindow::destroyGroup() {
m_sGroupData.head = false;
updateWindowDecos();
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -921,7 +895,7 @@ void CWindow::destroyGroup() {
addresses += std::format("{:x},", (uintptr_t)curr.get());
} while (curr.get() != this);
for (auto& w : members) {
for (auto const& w : members) {
if (w->m_sGroupData.head)
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr);
w->m_sGroupData.head = false;
@@ -929,14 +903,14 @@ void CWindow::destroyGroup() {
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked;
g_pKeybindManager->m_bGroupsLocked = true;
for (auto& w : members) {
for (auto const& w : members) {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(w);
w->updateWindowDecos();
}
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateWorkspaceWindowData(workspaceID());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID);
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
@@ -977,12 +951,16 @@ int CWindow::getGroupSize() {
}
bool CWindow::canBeGroupedInto(PHLWINDOW pWindow) {
static auto ALLOWGROUPMERGE = CConfigValue<Hyprlang::INT>("group:merge_groups_on_drag");
bool isGroup = m_sGroupData.pNextWindow;
bool disallowDragIntoGroup = g_pInputManager->m_bWasDraggingWindow && isGroup && !bool(*ALLOWGROUPMERGE);
return !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged
&& ((m_eGroupRules & GROUP_INVADE && m_bFirstMap) // window ignore local group locks, or
|| (!pWindow->getGroupHead()->m_sGroupData.locked // target unlocked
&& !(m_sGroupData.pNextWindow.lock() && getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group
&& !m_sGroupData.deny // source is not denied entry
&& !(m_eGroupRules & GROUP_BARRED && m_bFirstMap); // group rule doesn't prevent adding window
&& !(m_eGroupRules & GROUP_BARRED && m_bFirstMap) // group rule doesn't prevent adding window
&& !disallowDragIntoGroup; // config allows groups to be merged
}
PHLWINDOW CWindow::getGroupWindowByIndex(int index) {
@@ -1011,8 +989,9 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
return;
const auto PCURRENT = getGroupCurrent();
const bool FULLSCREEN = PCURRENT->m_bIsFullscreen;
const bool FULLSCREEN = PCURRENT->isFullscreen();
const auto WORKSPACE = PCURRENT->m_pWorkspace;
const auto MODE = PCURRENT->m_sFullscreenState.internal;
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
@@ -1020,7 +999,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow.lock();
if (FULLSCREEN)
g_pCompositor->setWindowFullscreen(PCURRENT, false, WORKSPACE->m_efFullscreenMode);
g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE);
PCURRENT->setHidden(true);
pWindow->setHidden(false); // can remove m_pLastWindow
@@ -1038,7 +1017,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
g_pCompositor->focusWindow(pWindow);
if (FULLSCREEN)
g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode);
g_pCompositor->setWindowFullscreenInternal(pWindow, MODE);
g_pHyprRenderer->damageWindow(pWindow);
@@ -1137,70 +1116,61 @@ bool CWindow::opaque() {
if (PWORKSPACE->m_fAlpha.value() != 1.f)
return false;
if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.buffer)
return m_pXWaylandSurface->surface->current.buffer->opaque;
if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.texture)
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;
// TODO: this is wrong
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 m_pWLSurface->resource()->current.buffer->opaque;
return m_pWLSurface->resource()->current.texture->m_bOpaque;
}
float CWindow::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 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");
bool border = true;
if (m_bIsFloating && *PNOBORDERONFLOATING == 1)
border = false;
if (*PNOBORDERONFLOATING)
m_sWindowData.noBorder = CWindowOverridableVar(m_bIsFloating, PRIORITY_LAYOUT);
else
m_sWindowData.noBorder.unset(PRIORITY_LAYOUT);
m_sSpecialRenderData.border = workspaceRule.border.value_or(border);
m_sSpecialRenderData.borderSize = workspaceRule.borderSize.value_or(-1);
m_sSpecialRenderData.decorate = workspaceRule.decorate.value_or(true);
m_sSpecialRenderData.rounding = workspaceRule.rounding.value_or(true);
m_sSpecialRenderData.shadow = workspaceRule.shadow.value_or(true);
m_sWindowData.borderSize.matchOptional(workspaceRule.borderSize, PRIORITY_WORKSPACE_RULE);
m_sWindowData.decorate.matchOptional(workspaceRule.decorate, PRIORITY_WORKSPACE_RULE);
m_sWindowData.noBorder.matchOptional(workspaceRule.noBorder, PRIORITY_WORKSPACE_RULE);
m_sWindowData.noRounding.matchOptional(workspaceRule.noRounding, PRIORITY_WORKSPACE_RULE);
m_sWindowData.noShadow.matchOptional(workspaceRule.noShadow, PRIORITY_WORKSPACE_RULE);
}
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;
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");
return *PBORDERSIZE;
return m_sWindowData.borderSize.valueOr(*PBORDERSIZE);
}
bool CWindow::canBeTorn() {
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint);
}
bool CWindow::shouldSendFullscreenState() {
const auto MODE = m_pWorkspace->m_efFullscreenMode;
return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL)));
static auto PTEARING = CConfigValue<Hyprlang::INT>("general:allow_tearing");
return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING;
}
void CWindow::setSuspended(bool suspend) {
@@ -1229,7 +1199,7 @@ void CWindow::setAnimationsToMove() {
void CWindow::onWorkspaceAnimUpdate() {
// clip box for animated offsets
if (!m_bIsFloating || m_bPinned || m_bIsFullscreen) {
if (!m_bIsFloating || m_bPinned || isFullscreen()) {
m_vFloatingOffset = Vector2D(0, 0);
return;
}
@@ -1283,7 +1253,15 @@ int CWindow::surfacesCount() {
return no;
}
int CWindow::workspaceID() {
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;
}
WORKSPACEID CWindow::workspaceID() {
return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace;
}
@@ -1322,7 +1300,7 @@ std::unordered_map<std::string, std::string> CWindow::getEnv() {
CVarList envs(std::string{buffer.data(), buffer.size() - 1}, 0, '\n', true);
for (auto& e : envs) {
for (auto const& e : envs) {
if (!e.contains('='))
continue;
@@ -1344,10 +1322,14 @@ void CWindow::activate(bool force) {
m_bIsUrgent = true;
if (!force &&
(!(*PFOCUSONACTIVATE || m_sAdditionalConfigData.focusOnActivate) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)))
if (!force && (!m_sWindowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)))
return;
if (!m_bIsMapped) {
Debug::log(LOG, "Ignoring CWindow::activate focus/warp, window is not mapped yet.");
return;
}
if (m_bIsFloating)
g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true);
@@ -1361,19 +1343,17 @@ void CWindow::onUpdateState() {
if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) {
bool fs = requestsFS.value();
if (fs != m_bIsFullscreen && m_bIsMapped)
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_FULL);
if (m_bIsMapped) {
g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value());
}
if (!m_bIsMapped)
m_bWantsInitialFullscreen = fs;
}
if (requestsMX.has_value() && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) {
bool fs = requestsMX.value();
if (fs != m_bIsFullscreen && m_bIsMapped)
g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_MAXIMIZED);
if (m_bIsMapped)
g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_MAXIMIZED, requestsMX.value());
}
}
@@ -1384,6 +1364,7 @@ void CWindow::onUpdateMeta() {
if (m_szTitle != NEWTITLE) {
m_szTitle = NEWTITLE;
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());
if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others
@@ -1477,7 +1458,7 @@ void CWindow::onX11Configure(CBox box) {
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_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock());
@@ -1521,9 +1502,6 @@ void CWindow::onX11Configure(CBox box) {
m_bCreatedOverFullscreen = true;
if (!m_sAdditionalConfigData.windowDanceCompat)
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(m_pSelf.lock());
}
@@ -1537,3 +1515,75 @@ void CWindow::warpCursor() {
else
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 const& 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 const& 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);
}
}
bool CWindow::isX11OverrideRedirect() {
return m_pXWaylandSurface && m_pXWaylandSurface->overrideRedirect;
}
bool CWindow::isModal() {
return (m_pXWaylandSurface && m_pXWaylandSurface->modal);
}

View File

@@ -6,7 +6,7 @@
#include "../config/ConfigDataValues.hpp"
#include "../defines.hpp"
#include "../helpers/AnimatedVariable.hpp"
#include "../helpers/Vector2D.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/TagKeeper.hpp"
#include "../macros.hpp"
@@ -16,6 +16,7 @@
#include "Popup.hpp"
#include "Subsurface.hpp"
#include "WLSurface.hpp"
#include "Workspace.hpp"
class CXDGSurfaceResource;
class CXWaylandSurface;
@@ -59,122 +60,131 @@ enum eSuppressEvents {
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>
class CWindowOverridableVar {
public:
CWindowOverridableVar(T val) {
value = val;
CWindowOverridableVar(T const& value, eOverridePriority priority) {
values[priority] = value;
}
CWindowOverridableVar(T const& value) {
defaultValue = value;
}
CWindowOverridableVar() = default;
~CWindowOverridableVar() = default;
CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> other) {
if (locked)
CWindowOverridableVar<T>& operator=(CWindowOverridableVar<T> const& other) {
// Self-assignment check
if (this == &other)
return *this;
locked = other.locked;
value = other.value;
for (auto const& value : other.values) {
values[value.first] = value.second;
}
return *this;
}
T operator=(T& other) {
if (locked)
return value;
value = other;
void unset(eOverridePriority priority) {
values.erase(priority);
}
bool hasValue() {
return !values.empty();
}
T value() {
if (!values.empty())
return std::prev(values.end())->second;
else
throw std::bad_optional_access();
}
T valueOr(T const& other) {
if (hasValue())
return value();
else
return other;
}
void forceSetIgnoreLocked(T val, bool lock = false) {
value = val;
locked = lock;
T valueOrDefault() {
return valueOr(defaultValue);
}
T operator*(T& other) {
return value * other;
eOverridePriority getPriority() {
if (!values.empty())
return std::prev(values.end())->first;
else
throw std::bad_optional_access();
}
T operator+(T& other) {
return value + other;
void matchOptional(std::optional<T> const& optValue, eOverridePriority priority) {
if (optValue.has_value())
values[priority] = optValue.value();
else
unset(priority);
}
bool operator==(T& other) {
return other == value;
}
bool operator>=(T& other) {
return value >= other;
}
bool operator<=(T& other) {
return value <= other;
}
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:
T value;
std::map<eOverridePriority, T> values;
T defaultValue; // used for toggling, so required for bool
};
struct SWindowSpecialRenderData {
CWindowOverridableVar<bool> alphaOverride = false;
CWindowOverridableVar<float> alpha = 1.f;
CWindowOverridableVar<bool> alphaInactiveOverride = false;
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
CWindowOverridableVar<bool> alphaFullscreenOverride = false;
CWindowOverridableVar<float> alphaFullscreen = -1.f; // -1 means unset
struct SWindowData {
CWindowOverridableVar<SAlphaValue> alpha = SAlphaValue{1.f, false};
CWindowOverridableVar<SAlphaValue> alphaInactive = SAlphaValue{1.f, false};
CWindowOverridableVar<SAlphaValue> alphaFullscreen = SAlphaValue{1.f, false};
CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset
CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset
// set by the layout
CWindowOverridableVar<int> borderSize = -1; // -1 means unset
bool rounding = true;
bool border = true;
bool decorate = true;
bool shadow = true;
};
struct SWindowAdditionalConfigData {
std::string animationStyle = std::string("");
CWindowOverridableVar<int> rounding = -1; // -1 means no
CWindowOverridableVar<bool> forceNoBlur = false;
CWindowOverridableVar<bool> forceOpaque = false;
CWindowOverridableVar<bool> forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
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> allowsInput = false;
CWindowOverridableVar<bool> dimAround = false;
CWindowOverridableVar<bool> forceRGBX = false;
CWindowOverridableVar<bool> keepAspectRatio = false;
CWindowOverridableVar<bool> decorate = true;
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> 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;
CWindowOverridableVar<bool> renderUnfocused = false;
CWindowOverridableVar<int> rounding;
CWindowOverridableVar<int> borderSize;
CWindowOverridableVar<std::string> animationStyle;
CWindowOverridableVar<Vector2D> maxSize;
CWindowOverridableVar<Vector2D> minSize;
CWindowOverridableVar<CGradientValueData> activeBorderColor;
CWindowOverridableVar<CGradientValueData> inactiveBorderColor;
};
struct SWindowRule {
@@ -192,6 +202,7 @@ struct SWindowRule {
int bFullscreen = -1;
int bPinned = -1;
int bFocus = -1;
std::string szFullscreenState = ""; // empty means any
std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any
};
@@ -201,6 +212,11 @@ struct SInitialWorkspaceToken {
std::string workspace;
};
struct sFullscreenState {
eFullscreenMode internal = FSMODE_NONE;
eFullscreenMode client = FSMODE_NONE;
};
class CWindow {
public:
static PHLWINDOW create(SP<CXDGSurfaceResource>);
@@ -254,10 +270,9 @@ class CWindow {
bool m_bFirstMap = false; // for layouts
bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bIsFullscreen = false;
bool m_bDontSendFullscreen = false;
bool m_bWasMaximized = false;
uint64_t m_iMonitorID = -1;
sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
MONITORID m_iMonitorID = -1;
std::string m_szTitle = "";
std::string m_szClass = "";
std::string m_szInitialTitle = "";
@@ -274,8 +289,6 @@ class CWindow {
// XWayland stuff
bool m_bIsX11 = false;
PHLWINDOWREF m_pX11Parent;
uint64_t m_iX11Type = 0;
bool m_bIsModal = false;
bool m_bX11DoesntWantBorders = false;
bool m_bX11ShouldntFocus = false;
float m_fX11SurfaceScaledBy = 1.f;
@@ -306,7 +319,7 @@ class CWindow {
bool m_bReadyToDelete = false;
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
Vector2D m_vOriginalClosedSize; // drawing the closing animations
SWindowDecorationExtents m_eOriginalClosedExtents;
SBoxExtents m_eOriginalClosedExtents;
bool m_bAnimatingIn = false;
// For pinned (sticky) windows
@@ -315,9 +328,6 @@ class CWindow {
// urgency hint
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.
PHLWINDOWREF m_pLastCycledWindow;
@@ -327,8 +337,7 @@ class CWindow {
std::vector<IHyprWindowDecoration*> m_vDecosToRemove;
// Special render data, rules, etc
SWindowSpecialRenderData m_sSpecialRenderData;
SWindowAdditionalConfigData m_sAdditionalConfigData;
SWindowData m_sWindowData;
// Transformers
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
@@ -342,6 +351,10 @@ class CWindow {
// animated tint
CAnimatedVariable<float> m_fDimPercent;
// animate moving to an invisible workspace
int m_iMonitorMovedFrom = -1; // -1 means not moving
CAnimatedVariable<float> m_fMovingToWorkspaceAlpha;
// swallowing
PHLWINDOWREF m_pSwallowed;
@@ -349,8 +362,8 @@ class CWindow {
bool m_bStayFocused = false;
// for toplevel monitor events
uint64_t m_iLastToplevelMonitorID = -1;
uint64_t m_iLastSurfaceMonitorID = -1;
MONITORID m_iLastToplevelMonitorID = -1;
MONITORID m_iLastSurfaceMonitorID = -1;
// for idle inhibiting windows
eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE;
@@ -383,7 +396,7 @@ class CWindow {
// methods
CBox getFullWindowBoundingBox();
SWindowDecorationExtents getFullWindowExtents();
SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props);
CBox getWindowMainSurfaceBox();
CBox getWindowIdealBoundingBoxIgnoreReserved();
@@ -405,22 +418,24 @@ class CWindow {
bool isHidden();
void applyDynamicRule(const SWindowRule& r);
void updateDynamicRules();
SWindowDecorationExtents getFullWindowReservedArea();
SBoxExtents getFullWindowReservedArea();
Vector2D middle();
bool opaque();
float rounding();
bool canBeTorn();
bool shouldSendFullscreenState();
void setSuspended(bool suspend);
bool visibleOnMonitor(CMonitor* pMonitor);
int workspaceID();
WORKSPACEID workspaceID();
bool onSpecialWorkspace();
void activate(bool force = false);
int surfacesCount();
bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize();
void updateSpecialRenderData();
void updateSpecialRenderData(const struct SWorkspaceRule&);
void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(void* ptr);
bool isInCurvedCorner(double x, double y);
@@ -450,6 +465,10 @@ class CWindow {
std::string fetchTitle();
std::string fetchClass();
void warpCursor();
PHLWINDOW getSwallower();
void unsetWindowData(eOverridePriority priority);
bool isX11OverrideRedirect();
bool isModal();
// listeners
void onAck(uint32_t serial);
@@ -479,7 +498,7 @@ class CWindow {
// For hidden windows and stuff
bool m_bHidden = false;
bool m_bSuspended = false;
int m_iLastWorkspace = WORKSPACE_INVALID;
WORKSPACEID m_iLastWorkspace = WORKSPACE_INVALID;
};
inline bool valid(PHLWINDOW w) {

View File

@@ -2,27 +2,31 @@
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) {
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmtpy);
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) {
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmpty);
workspace->init(workspace);
return workspace;
}
CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special, bool isEmtpy) {
CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) {
m_iMonitorID = monitorID;
m_iID = id;
m_szName = name;
m_bIsSpecialWorkspace = special;
m_bWasCreatedEmtpy = isEmtpy;
m_bWasCreatedEmpty = isEmpty;
}
void CWorkspace::init(PHLWORKSPACE self) {
m_pSelf = self;
m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"),
m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") :
g_pConfigManager->getAnimationPropertyConfig("workspacesIn"),
self, AVARDAMAGE_ENTIRE);
m_fAlpha.create(AVARTYPE_FLOAT,
m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), self,
m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), self,
AVARDAMAGE_ENTIRE);
m_fAlpha.setValueAndWarp(1.f);
@@ -45,15 +49,22 @@ void CWorkspace::init(PHLWORKSPACE self) {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self);
m_bPersistent = WORKSPACERULE.isPersistent;
if (self->m_bWasCreatedEmtpy)
if (self->m_bWasCreatedEmpty)
if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd)
g_pKeybindManager->spawn(*cmd);
g_pKeybindManager->spawnWithRules(*cmd, self);
g_pEventManager->postEvent({"createworkspace", m_szName});
g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)});
EMIT_HOOK_EVENT("createWorkspace", this);
}
SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName(bool perMonitor) const {
if (perMonitor)
return m_sPrevWorkspacePerMonitor;
return m_sPrevWorkspace;
}
CWorkspace::~CWorkspace() {
m_vRenderOffset.unregister();
@@ -71,12 +82,19 @@ CWorkspace::~CWorkspace() {
}
void CWorkspace::startAnim(bool in, bool left, bool instant) {
if (!instant) {
const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out");
m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME);
m_vRenderOffset.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME);
}
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
// set floating windows offset callbacks
m_vRenderOffset.setUpdateCallback([&](void*) {
for (auto& w : g_pCompositor->m_vWindows) {
for (auto const& w : g_pCompositor->m_vWindows) {
if (!validMapped(w) || w->workspaceID() != m_iID)
continue;
@@ -101,24 +119,24 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0);
} else {
m_fAlpha.setValueAndWarp(1.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 {
if (in) {
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_vRenderOffset = Vector2D(0, 0);
} else {
m_fAlpha.setValueAndWarp(1.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") {
@@ -139,10 +157,10 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? YDISTANCE : -YDISTANCE));
m_vRenderOffset.setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(0, left ? -YDISTANCE : YDISTANCE);
m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE);
}
} else {
// fallback is slide
@@ -152,10 +170,10 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) {
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0));
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0);
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0);
}
}
@@ -180,7 +198,7 @@ void CWorkspace::setActive(bool on) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
void CWorkspace::moveToMonitor(const int& id) {
void CWorkspace::moveToMonitor(const MONITORID& id) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
@@ -193,7 +211,7 @@ PHLWINDOW CWorkspace::getLastFocusedWindow() {
void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
if (!prev) {
m_sPrevWorkspace.iID = -1;
m_sPrevWorkspace.id = -1;
m_sPrevWorkspace.name = "";
return;
}
@@ -203,8 +221,13 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
return;
}
m_sPrevWorkspace.iID = prev->m_iID;
m_sPrevWorkspace.id = prev->m_iID;
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() {
@@ -219,15 +242,13 @@ std::string CWorkspace::getConfigName() {
}
bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
auto selector = removeBeginEndSpacesTabs(selector_);
auto selector = trim(selector_);
if (selector.empty())
return true;
if (isNumber(selector)) {
std::string wsname = "";
int wsid = getWorkspaceIDFromString(selector, wsname);
const auto& [wsid, wsname] = getWorkspaceIDNameFromString(selector);
if (wsid == WORKSPACE_INVALID)
return false;
@@ -262,7 +283,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
i = std::min(NEXTSPACE, std::string::npos - 1);
if (cur == 'r') {
int from = 0, to = 0;
WORKSPACEID from = 0, to = 0;
if (!prop.starts_with("r[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
@@ -352,7 +373,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
}
if (cur == 'w') {
int from = 0, to = 0;
WORKSPACEID from = 0, to = 0;
if (!prop.starts_with("w[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
@@ -365,7 +386,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
bool wantsCountVisible = false;
int flagCount = 0;
for (auto& flag : prop) {
for (auto const& flag : prop) {
if (flag == 't' && wantsOnlyTiled == -1) {
wantsOnlyTiled = 1;
flagCount++;
@@ -433,7 +454,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false;
}
int count;
WORKSPACEID count;
if (wantsCountGroup)
count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled),
wantsCountVisible ? std::optional<bool>(wantsCountVisible) : std::nullopt);
@@ -467,16 +488,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
return false;
break;
case 0: // fullscreen full
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_FULL)
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_FULLSCREEN)
return false;
break;
case 1: // maximized
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_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)
if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_MAXIMIZED)
return false;
break;
default: break;
@@ -498,7 +514,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
void CWorkspace::markInert() {
m_bInert = true;
m_iID = WORKSPACE_INVALID;
m_iMonitorID = -1;
m_iMonitorID = MONITOR_INVALID;
m_bVisible = false;
}

View File

@@ -4,36 +4,35 @@
#include <string>
#include "../defines.hpp"
#include "DesktopTypes.hpp"
#include "../helpers/MiscFunctions.hpp"
enum eFullscreenMode : int8_t {
FULLSCREEN_INVALID = -1,
FULLSCREEN_FULL = 0,
FULLSCREEN_MAXIMIZED
FSMODE_NONE = 0,
FSMODE_MAXIMIZED = 1 << 0,
FSMODE_FULLSCREEN = 1 << 1,
FSMODE_MAX = (1 << 2) - 1
};
class CWindow;
class CWorkspace {
public:
static PHLWORKSPACE create(int id, int monitorID, std::string name, bool special = false, bool isEmtpy = true);
static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true);
// use create() don't use this
CWorkspace(int id, int monitorID, std::string name, bool special = false, bool isEmpty = true);
CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true);
~CWorkspace();
// Workspaces ID-based have IDs > 0
// and workspaces name-based have IDs starting with -1337
int m_iID = -1;
WORKSPACEID m_iID = WORKSPACE_INVALID;
std::string m_szName = "";
uint64_t m_iMonitorID = -1;
// Previous workspace ID is stored during a workspace change, allowing travel
MONITORID m_iMonitorID = MONITOR_INVALID;
// Previous workspace ID and name is stored during a workspace change, allowing travel
// to the previous workspace.
struct SPrevWorkspaceData {
int iID = -1;
std::string name = "";
} m_sPrevWorkspace;
SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor;
bool m_bHasFullscreenWindow = false;
eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL;
eFullscreenMode m_efFullscreenMode = FSMODE_NONE;
wl_array m_wlrCoordinateArr;
@@ -58,7 +57,7 @@ class CWorkspace {
// last monitor (used on reconnect)
std::string m_szLastMonitor = "";
bool m_bWasCreatedEmtpy = true;
bool m_bWasCreatedEmpty = true;
bool m_bPersistent = false;
@@ -68,7 +67,7 @@ class CWorkspace {
void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on);
void moveToMonitor(const int&);
void moveToMonitor(const MONITORID&);
PHLWINDOW getLastFocusedWindow();
void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);
@@ -79,6 +78,8 @@ class CWorkspace {
void markInert();
SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const;
private:
void init(PHLWORKSPACE self);

View File

@@ -1,8 +1,22 @@
#include "IKeyboard.hpp"
#include "../defines.hpp"
#include "../helpers/VarList.hpp"
#include "../helpers/varlist/VarList.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() {
return HID_INPUT_CAPABILITY_KEYBOARD;
}
@@ -14,27 +28,173 @@ eHIDType IKeyboard::getType() {
IKeyboard::~IKeyboard() {
events.destroy.emit();
if (!xkbTranslationState)
return;
clearManuallyAllocd();
}
xkb_state_unref(xkbTranslationState);
xkbTranslationState = nullptr;
void IKeyboard::clearManuallyAllocd() {
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;
// 0 to avoid mods getting stuck if depressed during reload
updateModifiers(0, 0, 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) {
if (xkbTranslationState)
xkb_state_unref(xkbTranslationState);
if (xkbStaticState)
xkb_state_unref(xkbStaticState);
if (xkbState)
xkb_state_unref(xkbState);
if (xkbSymState)
xkb_state_unref(xkbSymState);
xkbState = nullptr;
xkbStaticState = nullptr;
xkbSymState = nullptr;
if (keymap) {
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);
xkbSymState = xkb_state_new(keymap);
return;
}
const auto WLRKB = wlr();
const auto KEYMAP = WLRKB->keymap;
const auto STATE = WLRKB->xkb_state;
const auto KEYMAP = xkbKeymap;
const auto STATE = xkbState;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
@@ -73,7 +233,9 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
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);
xkbSymState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT);
@@ -94,16 +256,17 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
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);
xkbSymState = xkb_state_new(NEWKEYMAP);
xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT);
}
std::string IKeyboard::getActiveLayout() {
const auto WLRKB = wlr();
const auto KEYMAP = WLRKB->keymap;
const auto STATE = WLRKB->xkb_state;
const auto KEYMAP = xkbKeymap;
const auto STATE = xkbState;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
@@ -119,29 +282,124 @@ std::string IKeyboard::getActiveLayout() {
return "none";
}
void IKeyboard::updateLEDs() {
auto keyboard = wlr();
if (!keyboard || keyboard->xkb_state == nullptr)
return;
std::optional<uint32_t> IKeyboard::getLEDs() {
if (xkbState == nullptr)
return {};
uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i]))
for (uint32_t i = 0; i < LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(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) {
auto keyboard = wlr();
if (!keyboard || keyboard->xkb_state == nullptr)
if (!xkbState)
return;
if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock()))
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 (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 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()) {
if (xkbSymState)
xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, modifiersState.group);
keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed,
.latched = modifiersState.latched,
.locked = modifiersState.locked,
.group = modifiersState.group,
});
}
}

View File

@@ -1,13 +1,24 @@
#pragma once
#include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp"
#include "../helpers/Vector2D.hpp"
#include "../helpers/math/Math.hpp"
#include <optional>
#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 {
public:
@@ -15,7 +26,7 @@ class IKeyboard : public IHID {
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual wlr_keyboard* wlr() = 0;
virtual SP<Aquamarine::IKeyboard> aq() = 0;
struct SKeyEvent {
uint32_t timeMs = 0;
@@ -24,6 +35,17 @@ class IKeyboard : public IHID {
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 {
CSignal key;
CSignal modifiers;
@@ -39,19 +61,43 @@ class IKeyboard : public IHID {
std::string rules = "";
};
void setKeymap(const SStringRuleNames& rules);
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
std::string getActiveLayout();
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 enabled = true;
// if the keymap is overridden by the implementation,
// don't try to set keyboard rules anymore, to avoid overwriting the requested one.
// e.g. Virtual keyboards with custom maps.
bool keymapOverridden = false;
xkb_layout_index_t activeLayout = 0;
xkb_state* xkbTranslationState = nullptr;
xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr,
*xkbSymState = nullptr /* Same as static but gets layouts */;
xkb_keymap* xkbKeymap = nullptr;
struct {
uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
} modifiersState;
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;
@@ -60,4 +106,9 @@ class IKeyboard : public IHID {
bool resolveBindsBySym = false;
WP<IKeyboard> self;
private:
void clearManuallyAllocd();
std::vector<uint32_t> pressedXKB;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,33 +4,34 @@
class CMouse : public IPointer {
public:
static SP<CMouse> create(wlr_pointer* mouse);
static SP<CMouse> create(SP<Aquamarine::IPointer> mouse);
virtual bool isVirtual();
virtual wlr_pointer* wlr();
virtual SP<Aquamarine::IPointer> aq();
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);
DYNLISTENER(motion);
DYNLISTENER(motionAbsolute);
DYNLISTENER(button);
DYNLISTENER(axis);
DYNLISTENER(frame);
CHyprSignalListener motion;
CHyprSignalListener motionAbsolute;
CHyprSignalListener button;
CHyprSignalListener axis;
CHyprSignalListener frame;
DYNLISTENER(swipeBegin);
DYNLISTENER(swipeEnd);
DYNLISTENER(swipeUpdate);
CHyprSignalListener swipeBegin;
CHyprSignalListener swipeEnd;
CHyprSignalListener swipeUpdate;
DYNLISTENER(pinchBegin);
DYNLISTENER(pinchEnd);
DYNLISTENER(pinchUpdate);
CHyprSignalListener pinchBegin;
CHyprSignalListener pinchEnd;
CHyprSignalListener pinchUpdate;
DYNLISTENER(holdBegin);
DYNLISTENER(holdEnd);
CHyprSignalListener holdBegin;
CHyprSignalListener holdEnd;
} listeners;
};

View File

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

View File

@@ -1,14 +1,13 @@
#pragma once
#include "IHID.hpp"
#include "../helpers/WLListener.hpp"
#include "../macros.hpp"
#include "../helpers/Vector2D.hpp"
#include "../helpers/Box.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/math/Math.hpp"
struct wlr_tablet;
struct wlr_tablet_tool;
struct wlr_tablet_pad;
AQUAMARINE_FORWARD(ITablet);
AQUAMARINE_FORWARD(ITabletTool);
AQUAMARINE_FORWARD(ITabletPad);
class CTabletTool;
class CTabletPad;
@@ -21,13 +20,12 @@ class CWLSurfaceResource;
*/
class CTablet : public IHID {
public:
static SP<CTablet> create(wlr_tablet* tablet);
static SP<CTablet> fromWlr(wlr_tablet* tablet);
static SP<CTablet> create(SP<Aquamarine::ITablet> tablet);
~CTablet();
virtual uint32_t getCapabilities();
virtual eHIDType getType();
wlr_tablet* wlr();
SP<Aquamarine::ITablet> aq();
enum eTabletToolAxes {
HID_TABLET_TOOL_AXIS_X = (1 << 0),
@@ -42,7 +40,7 @@ class CTablet : public IHID {
};
struct SAxisEvent {
wlr_tablet_tool* tool;
SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet;
uint32_t timeMs = 0;
@@ -58,7 +56,7 @@ class CTablet : public IHID {
};
struct SProximityEvent {
wlr_tablet_tool* tool;
SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet;
uint32_t timeMs = 0;
@@ -67,7 +65,7 @@ class CTablet : public IHID {
};
struct STipEvent {
wlr_tablet_tool* tool;
SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet;
uint32_t timeMs = 0;
@@ -76,7 +74,7 @@ class CTablet : public IHID {
};
struct SButtonEvent {
wlr_tablet_tool* tool;
SP<Aquamarine::ITabletTool> tool;
SP<CTablet> tablet;
uint32_t timeMs = 0;
@@ -100,27 +98,27 @@ class CTablet : public IHID {
CBox boundBox; // output-local
private:
CTablet(wlr_tablet* tablet);
CTablet(SP<Aquamarine::ITablet> tablet);
void disconnectCallbacks();
WP<Aquamarine::ITablet> tablet;
wlr_tablet* tablet = nullptr;
DYNLISTENER(destroy);
DYNLISTENER(axis);
DYNLISTENER(proximity);
DYNLISTENER(tip);
DYNLISTENER(button);
struct {
CHyprSignalListener destroy;
CHyprSignalListener axis;
CHyprSignalListener proximity;
CHyprSignalListener tip;
CHyprSignalListener button;
} listeners;
};
class CTabletPad : public IHID {
public:
static SP<CTabletPad> create(wlr_tablet_pad* pad);
static SP<CTabletPad> create(SP<Aquamarine::ITabletPad> pad);
~CTabletPad();
virtual uint32_t getCapabilities();
virtual eHIDType getType();
wlr_tablet_pad* wlr();
SP<Aquamarine::ITabletPad> aq();
struct SButtonEvent {
uint32_t timeMs = 0;
@@ -159,23 +157,22 @@ class CTabletPad : public IHID {
std::string hlName;
private:
CTabletPad(wlr_tablet_pad* pad);
CTabletPad(SP<Aquamarine::ITabletPad> pad);
void disconnectCallbacks();
WP<Aquamarine::ITabletPad> pad;
wlr_tablet_pad* pad = nullptr;
DYNLISTENER(destroy);
DYNLISTENER(ring);
DYNLISTENER(strip);
DYNLISTENER(button);
DYNLISTENER(attach);
struct {
CHyprSignalListener destroy;
CHyprSignalListener ring;
CHyprSignalListener strip;
CHyprSignalListener button;
CHyprSignalListener attach;
} listeners;
};
class CTabletTool : public IHID {
public:
static SP<CTabletTool> create(wlr_tablet_tool* tool);
static SP<CTabletTool> fromWlr(wlr_tablet_tool* tool);
static SP<CTabletTool> create(SP<Aquamarine::ITabletTool> tool);
~CTabletTool();
enum eTabletToolType {
@@ -199,7 +196,7 @@ class CTabletTool : public IHID {
};
virtual uint32_t getCapabilities();
wlr_tablet_tool* wlr();
SP<Aquamarine::ITabletTool> aq();
virtual eHIDType getType();
SP<CWLSurfaceResource> getSurface();
void setSurface(SP<CWLSurfaceResource>);
@@ -216,17 +213,13 @@ class CTabletTool : public IHID {
std::string hlName;
private:
CTabletTool(wlr_tablet_tool* tool);
void disconnectCallbacks();
CTabletTool(SP<Aquamarine::ITabletTool> tool);
WP<CWLSurfaceResource> pSurface;
wlr_tablet_tool* tool = nullptr;
DYNLISTENER(destroy);
WP<Aquamarine::ITabletTool> tool;
struct {
CHyprSignalListener destroySurface;
CHyprSignalListener destroyTool;
} listeners;
};

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