Compare commits

..

236 Commits

Author SHA1 Message Date
Vaxry
fe7b748eb6 props: bump version to 0.39.1 2024-04-16 17:01:03 +01:00
Vaxry
eeca50e3dc hyprpm: err out on missing runtime deps 2024-04-16 16:59:06 +01:00
vaxerski
9a66514e26 hyprpm: shallow since a week before commit date
timezones, etc.

ref #5612
2024-04-16 15:41:11 +01:00
vaxerski
32555e98dd window: remove input ref on unmap
ref #5605
2024-04-16 15:17:54 +01:00
Mihai Fufezan
79a139c949 flake.lock: update 2024-04-15 23:57:27 +03:00
FUFSoB
c99803af15 notifications: fix notifications on manually rotated monitor (#5599) 2024-04-15 21:47:39 +01:00
Vaxry
02cbf049d2 hyprpm: checkout branch and rev separately
sometimes the branch is garbled by incorrect packaging
2024-04-15 19:16:25 +01:00
Vaxry
ccbdce7c85 input: send an empty relative event after constraint motion events
ref #4015
2024-04-15 17:22:25 +01:00
Vaxry
3dbf8e936e cursor: add hyprcursor loggers 2024-04-15 16:45:08 +01:00
Vaxry
d1c2d524a0 misc: fix autocompletions for meson (hyprctl/hyprpm)
Signed-off-by: Florian sp1rit <sp1rit@disroot.org>
2024-04-15 16:02:22 +01:00
Jan Beich
2ea367839b build: Unbreak build on FreeBSD by adjusting dependencies (#5595)
* deps: add epoll-shim for some BSDs after 863c7b6072

ld: error: undefined symbol: timerfd_create
>>> referenced by EventLoopManager.cpp
>>>               src/Hyprland.p/managers_eventLoop_EventLoopManager.cpp.o:(CEventLoopManager::CEventLoopManager())

ld: error: undefined symbol: timerfd_settime
>>> referenced by EventLoopManager.cpp
>>>               src/Hyprland.p/managers_eventLoop_EventLoopManager.cpp.o:(CEventLoopManager::nudgeTimers())

See also
https://github.com/freebsd/freebsd-src/commit/af93fea71038
https://github.com/netbsd/src/commit/75f1bc6655cf

* deps: drop unused xcb-image after 45945a3e7d

$ pkg install <hyprland dependencies>
$ pkg install meson jq `pkg rquery %dn wlroots` hwdata
$ gmake all
[...]
-- Checking for modules 'xcb;xwayland;xcb-util;xcb-render;xcb-image;xcb-xfixes;xcb-icccm;xcb-composite;xcb-res;xcb-ewmh'
--   Package 'xcb-image' not found
CMake Error at /usr/local/share/cmake/Modules/FindPkgConfig.cmake:619 (message):
  The following required packages were not found:

   - xcb-image

Call Stack (most recent call first):
  /usr/local/share/cmake/Modules/FindPkgConfig.cmake:841 (_pkg_check_modules_internal)
  CMakeLists.txt:177 (pkg_check_modules)

See also
https://github.com/swaywm/wlroots/commit/ae7c3f3d1c56
2024-04-15 14:42:17 +01:00
Vaxry
1719905e7f CI: unshallow on checkout before sourcing the tarball 2024-04-15 02:05:45 +01:00
Vaxry
ce4c36392d hyprpm: minor fixes to hyprpm for shallow and versioned clones 2024-04-15 01:57:10 +01:00
vaxerski
67f47fbdcc [gha] Nix: update wlroots 2024-04-14 20:33:15 +00:00
thejch
043a40cd7a deps: update wlroots (#5592) 2024-04-14 21:32:19 +01:00
LivingCodeX
fd7ea4f27c constraint: Fix xwl cursor locking for scaled monitors (#5587)
* Fix xwl cursor locking for scaled monitors

* Add null check for window

* Replace m_fLastScale with m_fX11SurfaceScaledBy

* Improve code style

* Improve code style via clang-format
2024-04-14 21:31:50 +01:00
Vaxry
e93fbd7c4f props: bump ver to 0.39.0 2024-04-14 19:48:28 +01:00
go0d1uck
83ab0f2d66 keybindmgr: fix workspace_back_and_forth (#5585) 2024-04-14 14:54:00 +01:00
MightyPlaza
0634aaeac6 renderer: remove border on fullscreen (#5577)
modified:   src/render/Renderer.cpp
2024-04-14 00:16:26 +01:00
André Silva
61fe47189b build: update asan patch (#5562) 2024-04-13 22:13:08 +01:00
Yaroslav
9e4b2efe7e cmake: Some small cmake cleanups (#5572)
* remove unnecessary include

* cmake: use pkg_get_variable

We can find wayland-scanner executable and wayland-protocols dir by
taking advantage of this function, so no need to use find_program or
manually call pkgconf executable.

* cmake: remove explicit rdynamic option

CMAKE_ENABLE_EXPORTS=ON already implies rdynamic so it's redundant to
set the latter explicitly.

Also, CMAKE_ENABLE_EXPORTS is superseded by
CMAKE_EXECUTABLE_ENABLE_EXPORTS in cmake 3.27.

* cmake: make xcb-errors dep optional

xcb-errors is being used in wlroots, where it's optional. So make it
optional in hyprland as well
2024-04-13 14:40:28 +01:00
thejch
d96501442f core: Fix double special workspace (#5574)
* fix double special name

* fix special on another monitor

* remove extra stuff
2024-04-13 14:39:20 +01:00
thejch
582d6233c8 workspace: fix workspace name selector returning true early (#5571) 2024-04-13 01:55:17 +01:00
thejch
34396f55a2 master: change the mfact dispatcher to use splitratio (#4766)
* master layout: change the mfact dispatcher to use splitratio

* add space for concat
2024-04-13 01:54:18 +01:00
Vaxry
0c513ba91b CI: fix packaging 2024-04-12 20:46:21 +01:00
Vaxry
dd6fdf49d9 window: always unref workspace on unmap
fixes #5563
2024-04-12 19:52:01 +01:00
Vaxry
ddcdb56f2c CI: fix arch 2024-04-12 19:50:36 +01:00
bvr-yr
32147f5e91 hyprpm: fix wlroots path (#5567) 2024-04-12 19:49:33 +01:00
Mihai Fufezan
d8d0d3b20b Nix & Meson: switch to wlroots-hyprland 2024-04-12 20:39:00 +03:00
Vaxry
382b6d3f6b makefile: move wlr headers dir 2024-04-12 18:07:04 +01:00
Vaxry
0a70ccd099 Makefile: remove refs to libwlroots 2024-04-12 17:58:18 +01:00
vaxerski
e1e11f5a87 [gha] Nix: update wlroots 2024-04-12 15:32:45 +00:00
Vaxry
45945a3e7d deps: move from wlroots to wlroots-hyprland 2024-04-12 16:31:50 +01:00
Vaxry
b1a9430289 inhibitor: always destroy on window unmap
ref #5555
2024-04-12 00:18:58 +01:00
Jan-Peter Dhallé
e0a7cf5c30 master: fix full height when all windows master (#5549) 2024-04-12 00:05:30 +01:00
Vaxry
185a3b4881 swipe: nuke numbered
fixes #5424

use_r instead
2024-04-11 12:46:19 +01:00
TheOnlyMrCat
47e5b41fea renderer: Add dimaround layer rule (#4643) 2024-04-11 12:41:18 +01:00
Vaxry
ac0f3411c1 macros: fix no pch warning 2024-04-11 02:13:05 +01:00
Vaxry
abc131ec7b configmgr: fix header priority 2024-04-11 02:12:29 +01:00
Ben Landon
558d1be7e3 hyprpm: Improve Hyprpm Update Performance (#5530)
* hyprpm: only clone the required history

* hyprpm: don't include tracy when building headers in release mode

* chore: remove old, commented-out code

See https://github.com/hyprwm/Hyprland/pull/4585#discussion_r1474780294

* chore: format code properly
2024-04-10 17:33:50 +01:00
SoSeDiK
0b2f7a1b2f cursor: Fallback to xcursor if failed to render hyprcursor (#5534) 2024-04-10 17:29:17 +01:00
Sungyoon Cho
c35fa9bacc workspace: update windows when selector match could change (#5533)
* workspace: update windows when group updates

* workspace: update windows when floating toggle

* workspace: update windows when stop dragging window by mouse
2024-04-10 17:26:11 +01:00
Vaxry
b573c20125 monitor: add workspace null check to visible flag
ref #5524
2024-04-10 17:21:45 +01:00
JManch
303b9956b2 hyprctl: print monitor disabled status (#5525) 2024-04-10 09:50:00 +01:00
SoSeDiK
1343aa865d config: Don't override fullscreen opacity if only two opacities are provided (#5512) 2024-04-09 16:22:44 +01:00
SoSeDiK
f2addfb404 props: Parse border color props as gradient (#5513) 2024-04-09 16:14:53 +01:00
Sungyoon Cho
fcac25bcc2 workspace: Add count group flag in windowCount workspace selector prop (#5499)
* Add groupCount workspace selector prop

* Intergrate groupCount with windowCount
2024-04-09 12:08:38 +01:00
ErrorNoInternet
f6786f04d2 hyprpm: install shell completions 2024-04-09 12:38:06 +03:00
ErrorNoInternet
c7b87e0aed hyprctl: fix fish completions 2024-04-09 12:38:06 +03:00
postsolar
d0d1ba5918 hyprctl: fix zsh completions
The file missed a line required by all ZSH completions in order to be automatically loaded
2024-04-09 07:08:54 +03:00
dranull
a06272ae55 input: Option for handling off-window axis events (#4177) 2024-04-08 23:35:21 +01:00
Mihai Fufezan
277f2bb76a Nix: add pkgconf 2024-04-08 20:54:06 +03:00
Vaxry
0457c2e348 pkg-config -> pkgconf for hyprpm and cmake 2024-04-08 20:54:06 +03:00
Tom Englund
125a8f7e07 workspace: fix crash on destruction of compositor (#5495)
when the compositor destructs because of exiting hyprland the
hookmanager and eventmanager is already destroyed, add an if check in
the destructor of workspace so it doesnt segfault on exit.
2024-04-08 18:28:11 +01:00
Vaxry
63e3668529 style: run clang-format 2024-04-08 15:33:02 +01:00
Tom Englund
db91d949f7 compositor: move wl_display_destroy_clients (#5498)
if enough clients are open when destructing the compositor destroying
clients will emit a wl_surface_unmap that a WLListener catches and doing
so it calls listener_unmapLayerSurface that tries to iterate over input
manager that is already destroyed, move the destruction of clients above
g_pInputManager.reset() and removeAllSignals() to ensure we dont
segfault at exit.
2024-04-08 15:32:31 +01:00
Vaxry
785d9d9521 config: verify string length in wrv2 before calling back
ref #5431
2024-04-08 15:27:13 +01:00
SoSeDiK
43b96f03b5 props: Allow setting per-window fullscreen opacity (#5470) 2024-04-07 23:19:02 +01:00
MightyPlaza
df1a3a978d input: don't remove pinned focus on workspace change (#5486)
modified:   src/helpers/Monitor.cpp
2024-04-07 23:13:56 +01:00
Vaxry
7d989f2cf0 damageSurface: don't correct smallVec twice 2024-04-07 22:25:34 +01:00
Vaxry
863c7b6072 eventloop: move timers to an event loop fd
fixes #5481
2024-04-07 21:55:29 +01:00
Mihai Fufezan
c0d283016b flake.lock: update
Contains hyprcursor 1.6
2024-04-07 22:52:10 +03:00
LOSEARDES77
20899d0df2 hyprpm: add shell completions (#5423)
* hyprpm: add completions

* hyprctl: correct spell mistakes

* Apply fixes

* makefile: correct shell completion paths

* makefile: remove complletions on uninstalling
2024-04-07 19:39:46 +03:00
Yaroslav Lelkin
b50182326c cmake: make sure that OpenGL::EGL is populated
bump cmake version cause 3.27 is the version where "... COMPONENTS
GLESx" option is introduced. See
https://cmake.org/cmake/help/latest/module/FindOpenGL.html
2024-04-07 19:08:25 +03:00
thejch
89f775aec2 master: fix crash (#5472) 2024-04-07 15:21:12 +01:00
Junxuan Liao
d657b59f70 IME: fix IME popup mouse inputs (again) (#5417)
`lastBoxLocal`'s size should be the actual popup's size instead of the cursor
rectangle's size. Also, the rectangle position is now relative to the popup.
(Actually fixes #5255 imho.)

One thing #3922 missed was handling focus held by buttons. Let's hope I get
it right this time.
2024-04-07 15:15:50 +01:00
Vaxry
f2a848cbcc core: Event loop rework (#5466)
* Event loop rework

* revert missed
2024-04-07 03:31:51 +01:00
thejch
9f1604e4b0 input: Dont set active monitor when simulating mouse movement (#5465)
* fix mouse simulation switching focusedmon

* fix some warnings with wrong enum
2024-04-07 01:07:21 +01:00
thejch
e80bccad51 master: fix workspace orientation not being restored after workspace rule no longer applies (#5463) 2024-04-06 23:49:38 +01:00
Vaxry
ff114cf6f9 input: fix focus on maximized bg surfaces 2024-04-06 18:59:23 +01:00
Vaxry
d846e82832 makefile: add patch option to make asan 2024-04-06 18:50:04 +01:00
Vaxry
fa79aacea3 constraint: fix possible uaf on double destruction
ref #5448
2024-04-06 18:43:17 +01:00
fred21O4
265c7924d8 flake.nix: add hyprcursor follows (#5435)
fixes a duplicate hyprlang instance sometimes being created due to hyprcursor not following hyprlands instance
2024-04-06 19:18:43 +03:00
Mihai Fufezan
3d64b0e9f0 flake.lock: update 2024-04-06 19:09:37 +03:00
Sungyoon Cho
04d067d78b IME: fix race condition on closing window (#5455) 2024-04-06 15:54:02 +01:00
staz
1596e2d1f7 workspacerules: add back on-created-empty functionality (#5452)
* workspacerules: add back on-created-empty functionality

* clang format

* workspacerules: spawn on-created-empty window while initializing CWorkspace

* clang format

* configManager: fix typo

---------

Co-authored-by: Your Name <you@example.com>
2024-04-06 15:53:32 +01:00
Vaxry
6cea710ac8 scripts: switch to branch --show-current for branch in generateVersion 2024-04-06 15:40:06 +01:00
Vaxry
f081a4300f input: fixup background layer checking on maximized 2024-04-06 15:18:58 +01:00
Vaxry
159444c45b compositor: fix ghost fadingOut windows remaining after cleanup 2024-04-06 14:59:30 +01:00
Vaxry
f8c22916ab compositor: remove windows from fadingOut properly 2024-04-06 14:51:35 +01:00
Vaxry
24734fbf1d subsurface: init existing subsurfaces on children creations
fixes #5333
2024-04-06 03:09:20 +01:00
Vaxry
dab149e4a6 core: fix compile without pch
fixes #5445
2024-04-05 21:23:28 +01:00
Vaxry
b5b1c0137d CColor: fix getAsHex 2024-04-05 21:23:06 +01:00
Vaxry
094bce8118 core: simplify sanityCheckWorkspaces 2024-04-05 19:43:51 +01:00
Vaxry
4909b0f350 monitor: unset visible flag from ws on disconnect
ref #5443
2024-04-05 19:25:40 +01:00
Vaxry
965a2e5b21 hooksystem: attempt allocating pages in linear order 2024-04-05 17:16:09 +01:00
Vaxry
f815a33f64 workspace: remove monitor and visible flags on inert 2024-04-05 16:57:49 +01:00
Vaxry
0051b078a1 monitor: check for invalid workspaces in onConnect
ref #5443
2024-04-05 16:57:49 +01:00
thejch
1e8f57c734 workspacerules: fix workspace rule loops (#5433) 2024-04-05 16:54:30 +01:00
Martin Sundhaug
942172d2dc hooksystem: Fix miscalculation in comment (#5442) 2024-04-05 12:56:53 +01:00
bvr-yr
baad44b4ca hyprpm: fix incorrect commits number parsing (#5437) 2024-04-05 04:40:44 +01:00
Vaxry
12d75c0c26 hyprpm: ignore version checks for shallow clones 2024-04-05 03:00:34 +01:00
Vaxry
1ae592fcd9 hyprpm: add support for minimum versions 2024-04-05 00:46:37 +01:00
Vaxry
51b3148f09 hyprpm: print more info on build failures 2024-04-05 00:23:05 +01:00
Vaxry
1454c6213e window: fix invalid last workspace id
ref #5432
2024-04-04 22:49:15 +01:00
Vaxry
ec2cc79c65 renderer: avoid double-rendering ls-es on fadingOut
fixes #5295
2024-04-04 22:43:57 +01:00
Vaxry
0569b9c300 hooksystem: manually map trampoline addresses
better patching of rip calls as we are close enough to just change them up
2024-04-04 18:50:37 +01:00
Vaxry
cba9c5ff95 core: fix visibility flags in moveWorkspaceToMonitor
fixes #5416
2024-04-04 18:30:50 +01:00
Sungyoon Cho
c4b660a339 IME: fix crash on restarting IME (#5428) 2024-04-04 17:34:04 +01:00
Vaxry
4f3e90ad2d popups: more safety in damage checking 2024-04-04 16:42:30 +01:00
end-4
9b8ef9206d layers: separate anim configs for open/close (#5421) 2024-04-04 16:41:09 +01:00
zakk4223
846162cce1 hyprpm: Use proper path to update repo when processing user provided revision (#5414) 2024-04-04 16:33:36 +01:00
Mihai Fufezan
81766647f2 hyprctl: fix grammar mistakes in completions 2024-04-04 10:49:25 +03:00
LOSEARDES77
1b43cd5231 hyprctl: Add shell completions (#5404) 2024-04-04 10:21:20 +03:00
Vaxry
b7d71bc0e1 keybinds: fix spammy warning 2024-04-04 01:16:47 +01:00
Vaxry
9cf563065a layouts: add missing include 2024-04-04 01:10:46 +01:00
Vaxry
36a8ae9bda input: allow focus to bottom layers on maximized in reserved 2024-04-03 21:57:19 +01:00
Micovec
949eb42613 hyprctl: improve help pages (#5385) 2024-04-03 23:41:10 +03:00
Vaxry
d605e47511 renderer: block screen shader on screencopy 2024-04-03 21:35:16 +01:00
Vaxry
10146f5ec5 core: fix some crash conditions around workspace ptrs in CWindow
ref #5402, supersedes #5409
2024-04-03 20:42:38 +01:00
Vaxry
d88d589880 swipe: add events 2024-04-03 19:20:47 +01:00
Vaxry
93915502d2 blur: block modif only on no new optimize 2024-04-03 17:08:11 +01:00
Vaxry
91061a2084 opengl: fix modif in blur 2024-04-03 15:08:29 +01:00
Vaxry
64964c4e3b renderer: render back layer for workspace-less passes 2024-04-03 14:28:15 +01:00
Vaxry
3981f85e94 opengl: log framebuffer errors 2024-04-03 14:24:15 +01:00
Vaxry
efdc1af044 renderer: some fixes for renderModif 2024-04-03 14:09:58 +01:00
Vaxry
347b839034 workspaces: add visible flag 2024-04-03 10:09:48 +01:00
thejch
fbdaf74a82 master: fix swapped workspaces (#5397) 2024-04-03 01:22:59 +01:00
thejch
3965faafac master: fix center resizing (#5394) 2024-04-03 01:22:27 +01:00
MightyPlaza
153c8f35ce workspace: fix special unnamed workspace rules (#5390)
modified:   src/desktop/Workspace.cpp
2024-04-02 22:58:45 +01:00
Vaxry
ef23ef60c5 Workspace/core: Refactor workspace storage (#5380)
* refactor workspaces to use ptrs

* clang-format
2024-04-02 20:32:39 +01:00
Vaxry
fc0a7af7ba IME: fix blurry ime on scaled
ref #5387
2024-04-02 16:10:55 +01:00
Vaxry
05eb2d4af2 master: guard window in moveWindowTo
fixes #5374
2024-04-02 12:46:15 +01:00
Sungyoon Cho
04a35891a1 IME: fix incorrect popup damage (#5383) 2024-04-02 12:22:41 +01:00
Vaxry
2e5b146e57 workspace: remove lastFocusedWindow on unmap 2024-04-02 12:10:03 +01:00
Vaxry
af3a61a4e4 core: assert attempted UAFs in windowExists
in prep of removing the thing altogether
2024-04-02 01:15:58 +01:00
Jan Beich
c377caee7a hyprerror: align 32-bit types after 4c796683c0 (#5375)
src/hyprerror/HyprError.cpp:64:33: error: no matching function for call to 'min'
    const auto   VISLINECOUNT = std::min(LINECOUNT, *LINELIMIT);
                                ^~~~~~~~
/usr/include/c++/v1/__algorithm/min.h:40:1: note: candidate template ignored: deduced conflicting types for parameter '_Tp' ('int' vs. 'long long')
min(const _Tp& __a, const _Tp& __b)
^
/usr/include/c++/v1/__algorithm/min.h:51:1: note: candidate template ignored: could not match 'initializer_list<_Tp>' against 'int'
min(initializer_list<_Tp> __t, _Compare __comp)
^
/usr/include/c++/v1/__algorithm/min.h:60:1: note: candidate function template not viable: requires single argument '__t', but 2 arguments were provided
min(initializer_list<_Tp> __t)
^
/usr/include/c++/v1/__algorithm/min.h:31:1: note: candidate function template not viable: requires 3 arguments, but 2 were provided
min(const _Tp& __a, const _Tp& __b, _Compare __comp)
^
2024-04-01 21:18:18 +01:00
Vaxry
3875679755 props: bump ver to 0.38.0 2024-04-01 19:30:37 +01:00
Sungyoon Cho
db1506130b IME: Fix ime popup coordinates and artifacts (#5373)
* ime: fix incorrect popup coordinate

* ime: fix popup artifacts
2024-04-01 16:37:59 +01:00
Vaxry
108163f1e5 animations: simplify window loop 2024-04-01 16:22:24 +01:00
thejch
7513c0cea5 renderer: Fix layer and window damage sometimes missing 1 frame (#5370)
* fix the layer and window damage missing 1 frame sometimes

* remove extra loop
2024-04-01 16:21:45 +01:00
thejch
800dbf71b0 renderer: Fix rendering when swiping workspaces (#5367)
* fix rendering on swiping

* add alpha check

* fix floating fs check
2024-04-01 16:16:18 +01:00
Vaxry
416b3d6167 socket2: sanitize data for newlines 2024-04-01 03:54:11 +01:00
thejch
ef7ac53e99 master: Make master workspace orientation rule dynamic (#5339)
* make master workspace orientation rule dynamic

* fix rebase

* fix special ws resizing

* style
2024-04-01 03:02:47 +01:00
thejch
9ae0c47a21 deco: fix groupbar offset (#5364) 2024-04-01 02:58:21 +01:00
Sungyoon Cho
ecc1f22e05 textinput: fix typo (#5365) 2024-04-01 00:41:00 +01:00
Micovec
8cb38d41d2 hyprctl: fix plugin list on no plugins (#5357) 2024-03-31 21:45:22 +01:00
Vaxry
9e8f051896 avar: minor fixes 2024-03-31 21:43:08 +01:00
Vaxry
64c8ba2fb1 avar: fix warp onEnd conditions
ref #5348
2024-03-31 21:34:11 +01:00
Vaxry
4156b55cf9 textinput: send deactivate on disable ti
ref #5288
2024-03-31 21:30:36 +01:00
thejch
e1e41e5448 reenderer: Add 1 border damage to fix number rounding issues (#5343)
* add 1 to border damage to avoid rounding issues

* add 1 to rounding too
2024-03-31 14:59:22 +01:00
thejch
16a9c16d9f renderer/animations: Fix various inaccurate damage tracking issues and offsets (#5297) 2024-03-31 02:14:26 +01:00
Zach DeCook
1cc9a44318 input: Fix incorrect keyboard focus taken when no window was present (#5337)
A non-keyboard layer never needs keyboard focus
2024-03-31 00:50:25 +00:00
thejch
5e8c25d498 core: match all workspace rules instead of the first one only (#5340) 2024-03-31 00:49:53 +00:00
Aqa-Ib
1aed45f61d core: Fix resizeparams (#5262)
* Revert a94b902

* Fix resizeparams using CVarList

* clang-format

* fix

* Use 's' as delimiter

* remove size checks

* fix tabs

* fix mixing tabs and spaces
2024-03-31 00:48:39 +00:00
Vaxry
77f26997fd IME: don't assert on lock mismatch, just fix it 2024-03-30 17:01:02 +00:00
thejch
906e498144 dispatchers: open special ws on active monitor instead of mouse monitor (#5330) 2024-03-30 16:58:18 +00:00
thejch
a17d7ba87b dispatchers: fix swap workspaces wrong positioning of floating windows (#5328) 2024-03-30 16:57:43 +00:00
Vaxry
6fb8f50205 hyprpm: avoid crashes on corrupted headers
ref #5329
2024-03-30 03:09:22 +00:00
Vaxry
54376d7b5f compositor: remove windows from fading out on destroy
ref #5321
2024-03-29 19:07:18 +00:00
Vaxry
3d1bf1405e keybinds: add binds:disable_keybind_grabbing
fixes #5273
2024-03-29 18:57:16 +00:00
Muhamed Hobi
53aa184d20 makefile: Remove old headers first (#5316)
Windows.cpp was moved and I found myself having both versions in my include. Clear out the headers before dumping new ones.
2024-03-29 14:07:33 +00:00
Vaxry
fcd9d77b64 layout: improve initial size prediction for floating 2024-03-29 00:43:50 +00:00
Vaxry
2930c5cb6f animvar: fixup update callbacks and cleanup 2024-03-29 00:23:23 +00:00
Mihai Fufezan
d8429eebc6 flake.lock: update
Fixes #5301
2024-03-28 18:44:00 +02:00
MightyPlaza
187caf4187 layers: don't change workspace on layer restore focus (#5308)
modified:   src/events/Layers.cpp
2024-03-28 14:15:34 +00:00
MightyPlaza
647d5a4ffc layers: fix bottom slide animation (#5307)
modified:   src/helpers/WLClasses.cpp
2024-03-28 14:14:27 +00:00
Vaxry
2571875453 format: fix format 2024-03-28 02:28:22 +00:00
MightyPlaza
c24034eb9d core: fix fullscreen + floating focus change (#5291)
modified:   src/Compositor.cpp
2024-03-28 02:08:21 +00:00
Vaxry
0869f65b0b input: add misc:hide_cursor_on_key_press
fixes #3045
2024-03-28 02:07:06 +00:00
Vaxry
132ab8d035 layers: add animation direction overrides
fixes #5285
2024-03-28 01:39:29 +00:00
vaxerski
93d0511471 layershell: update render pos and size in arrange
fixes #5258
2024-03-27 16:30:08 +00:00
Sungyoon Cho
ae52b7f468 textinput: fix ime when opening multiple windows (#5281) 2024-03-26 15:16:09 +00:00
Khalid
9b7ae25ae8 hyprctl: output json with --batch if requested (#5277) 2024-03-26 13:38:54 +00:00
vaxerski
1a0b8d1263 renderer: minor fixes to misaligned reported surface rendering
fixes #5257
2024-03-26 13:35:03 +00:00
Vaxry
a9d7526aae core: ensure m_pLastMonitor validity over unsafe state
ref #5241
2024-03-26 02:26:19 +00:00
thejch
414e37996d github: fix github issue template crash dir (#5269) 2024-03-26 02:21:31 +00:00
Vaxry
ae17e900e7 layer-shell: render popups above everything 2024-03-25 16:20:30 +00:00
Vaxry
ca17a89d86 renderer: allow blurring ls popups 2024-03-25 16:09:02 +00:00
thejch
356414639f core: fix missing workspace events during swapping (#5251) 2024-03-25 01:50:41 +00:00
dmayle
6b28bf563e keybinds: Fix exit trigger by moving it to monitor.frame (#5240) 2024-03-25 01:46:59 +00:00
thejch
8001b96bb5 renderer: dont render fullscreen special on wrong monitor (#5249) 2024-03-25 01:41:56 +00:00
Vaxry
89543e8e3c cursormgr: don't set x theme in changeTheme 2024-03-24 20:48:56 +00:00
Brett Alcox
03e99f93ae renderer: forward decl for b_pch=false (#5250) 2024-03-24 20:38:10 +00:00
Vaxry
294ff8609f cursormgr: log theme loading failures 2024-03-24 19:39:56 +00:00
Vaxry
1e82d5a04d ime: fix build without pch 2024-03-24 17:19:35 +00:00
Vaxry
5cc4bf699c IME: Refactor and fixup popups 2024-03-24 16:08:25 +00:00
Vaxry
acf15e5579 text-input: reset lock counter on surface destroy
fixes #5231
2024-03-24 15:00:00 +00:00
Vaxry
86dc46ffea animationmgr: use realpos and size for border damage
fixes #5239
2024-03-24 03:09:46 +00:00
Vaxry
09e1128da2 cursormgr: initialize size to 0
Because the ctor expects that. Ref #5237
2024-03-24 02:21:36 +00:00
Vaxry
432924b372 xwayland: assign wlr_surface on associate 2024-03-24 02:21:36 +00:00
thejch
c7fbea3368 animations: Fix animation issue in focusworkspaceoncurrentmonitor (#5202)
* dont render when workspace offset

* add guard

* can remove useless code now if workspace offset is not taken into account

* clang-format

* when special workspace is moved, set anim to move

* add offset back

* make it a configurable option because some folks apparently can't align their monitors correctly and may not want this feature😔

* remove config option
2024-03-23 22:14:50 +00:00
Vaxry
295128ab2a window: assign surface on create
ref #5076
2024-03-23 22:10:37 +00:00
Sungyoon Cho
2d5fda4810 input: fix crash with text-input-v1 (#5234) 2024-03-23 21:12:27 +00:00
Vaxry
0d91f82d83 config: be a bit louder in the disabled log warning 2024-03-23 21:11:00 +00:00
Khalid
059e85ae69 input: Add options to set tablet's active area (#5199)
* Add options to set tablet's active area

* Set tablet's active area in `setTabletConfigs`

* Fix formatting for new variables in ConfigManager

* Report tablet's physical size with hyprctl
2024-03-23 20:31:03 +00:00
fufexan
0dfdb6678f [gha] Nix: update inputs 2024-03-23 00:03:18 +00:00
Vaxry
9f2ed02f35 IME/TI: Fixes and refactoring
Fixes #5189
2024-03-22 23:08:52 +00:00
Vaxry
8c88689faf IME: guard unfocused TIs in leave 2024-03-22 18:58:28 +00:00
Vaxry
568b352b23 cmakelists: remove oopsie 2024-03-22 18:52:07 +00:00
Vaxry
d2b42e29c6 IME: fix crashes with destroyed text-inputs
ref #5189
2024-03-22 18:45:28 +00:00
Vaxry
461757e2fb scripts: fix asan patch 2024-03-22 18:45:28 +00:00
MightyPlaza
397e08c16a input: focus window on mouse down on groupbar (#5224)
modified:   src/render/decorations/CHyprGroupBarDecoration.cpp
2024-03-22 17:41:20 +00:00
Holger Schurig
c7c0e795d2 CGradientValueData: fix toString() method (#5220) 2024-03-22 17:34:51 +00:00
drendog
9bad62b85f layershell: release all mouse buttons before focus on new ls (#5219) 2024-03-22 01:28:50 +00:00
Philipp Schilk
a94b902bef windowrules: Fix resizeparams parsing. (#5206)
Parsing of resizeparams/relative vec2 did not correctly handle
multiple spaces between x and y arguments, causing the following
to fail to parse:

bind = $mainMod CTRL, h, resizeactive,  10       0

This is unexpected, because most other config values are whitespace
insensitive.
2024-03-21 15:18:24 +00:00
Andrey Donets
997ee82bdf hyprctl: add missing commands to usage (#5211) 2024-03-21 14:57:06 +00:00
Praneeth Jain
f1d06b773f hyprpm: add missing newline (#5207) 2024-03-21 14:50:19 +00:00
jill
ee00cb1dd8 opengl: report shader compilation errors from screen_shader (#5138)
* opengl: report shader compilation errors from screen_shader

* opengl: prefer .data()

* opengl: move shader error logging to logError

* opengl: quick glGetShaderiv -> glGetProgramiv fix

* opengl: typo fix

* opengl: format fixes

* opengl: minor compile fixes

* opengl: logError -> logShaderError
2024-03-21 14:46:23 +00:00
zakk4223
4c796683c0 config: Config error limit/hyprctl (#5165)
* Add error_limit to limit the number of config error messages shown in notification

* Add configerrors hyprctl command

* Formatting

* Formatting for not my code

* Use CVarList, add escapeJSONStrings

* Add indication there are more undisplayed errors

* Restore suppress_errors; move getErrors() to ConfigManager

* Formatting, wtf

* Format
2024-03-21 01:55:13 +00:00
Brett Alcox
214ec82ba7 build: fix builds without pch (#5198) 2024-03-21 01:54:10 +00:00
Horror Proton
bfc95e992d swipe: fix nullptr in onSwipeUpdate (#5191) 2024-03-20 18:13:31 +00:00
Nathan Hadley
d904f51716 README: Fix Preview B image (#5188) 2024-03-20 18:11:40 +00:00
Vaxry
361357095c workspace: fix selectors with special:
fixes #5187
2024-03-20 18:06:03 +00:00
Khalid
9ddf1b105e tablet: Add left_handed option for tablets (#5178)
* Add left_handed option for tablets

* Update left_handed tablet option's fallback string
2024-03-20 04:00:43 +00:00
thejch
95ac8a34b1 workspace: fix integer overflow in selector parser (#5177) 2024-03-20 02:33:39 +00:00
Vaxry
8593c45be3 refactor: move window.hpp to desktop/ 2024-03-20 01:44:51 +00:00
Vaxry
f6038837bc constraint: do not disable constraints in destroy
fixes #5170
2024-03-20 01:30:41 +00:00
Vaxry
07ab3b8cd6 hyprpm: log shell in build without fails 2024-03-19 22:12:55 +00:00
Vaxry
05cd6d3df1 config/workspace: added workspace selectors 2024-03-19 20:56:20 +00:00
Vaxry
c32b2331d1 constraint: set active flag before propagating props
fixes #5170
2024-03-19 18:55:17 +00:00
phonetic112
bcba3951f4 input: Only limit drag resizes (#5164)
* only limit drag resizes

* change to not equals

* remove extra parentheses
2024-03-19 16:03:31 +00:00
joshua
5c1097cbc1 IME: Improve handling of text-input and ime-relay (#5147)
* input: Handling multiple surfaces for the text-input-v1 protocol implementation and imporve InputMethodRelay logic

fixes #2708

* clang-format

* minor style nits

---------

Co-authored-by: Vaxry <vaxry@vaxry.net>
2024-03-19 15:54:33 +00:00
Epilepsy Gatherings
05c84304cc github: remove redundant instruction (#5163)
v0.34.0 is pretty old at this point.
2024-03-19 02:53:51 +00:00
Vaxry
7617c03dfd window: set config only when both props end anims 2024-03-19 02:53:13 +00:00
thejch
e6532ba024 animations: Fix incorrect animation when manually moving a window when its being created (#5141)
* fix incorrect rendering when manually moving a window when its being created

* add setAnimationsToMove
2024-03-19 02:52:52 +00:00
Vaxry
7a31c954e5 tablet: minor focus fixes
ref #3004
2024-03-19 02:45:11 +00:00
Vaxry
49f5fd59ad opengl: minor adjustment to getPreferredReadFormat
fixes #4791
2024-03-19 02:42:39 +00:00
Vaxry
7283dde878 screenShader: allow camel for screensize
ref #5059
2024-03-18 23:51:32 +00:00
Vaxry
4ffcdc41ff animations: fix layer slide with fade
fixes #5151
2024-03-18 18:29:57 +00:00
Vaxry
4b74123649 socket2: add pin event
fixes #4778
2024-03-18 18:11:20 +00:00
Vaxry
5eb33ff4d8 screenshader: add screen_size uniform
fixes #5059
2024-03-18 16:35:22 +00:00
Vaxry
7587cadd0a renderer: add support for gles3.2 screen shaders 2024-03-18 04:15:04 +00:00
Vaxry
c34ad12183 cursormgr: scale hotspot with buffer 2024-03-17 19:00:21 +00:00
Vaxry
30c5911718 renderer: minor fixups for misaligned surface rendering offsets
fixes #5136
2024-03-17 16:08:59 +00:00
Zach DeCook
3c21f5e07b swipe: Touchscreen workspace swipe (#4489)
* Workspace Swipe: Refactor update and end functions

* Touch: Implement workspace swipe better

ignoring additional fingers and new touches

allow gaps-right and gaps-left to be different
2024-03-17 15:43:59 +00:00
djvs
3ed3b34c4a keybinds: add Dispatchers for "force float" and "force tiling" (non-toggle) (#5137)
---------

Co-authored-by: djvs <djvs@users.noreply.github.com>
2024-03-17 15:41:43 +00:00
Vaxry
e68c07d809 renderer: don't render window on other mons during anim in
fixes #5139
2024-03-17 01:05:26 +00:00
thejch
0387528c56 master: fix moving fullscreen workspace and remove duplicate code (#5131) 2024-03-17 00:15:12 +00:00
Vaxry
0e87a08e15 renderer: disable surface adjustments for misaligned reported when manual resizing
ref #5135
2024-03-16 17:56:09 +00:00
Vaxry
3162739e1b renderer: don't translate surface box on interactive resizes with non-updated sizes
closes #5135
2024-03-16 17:12:29 +00:00
Omar
e566be7847 LICENSE: Update year (#5132)
Updating the license year from 2022-2023 to 2022-2024
2024-03-16 16:57:45 +00:00
Mihai Fufezan
bd332a79e7 Nix: match derivation to Nixpkgs 2024-03-16 18:12:42 +02:00
Vaxry
c5e28ebcfe props: bump ver 0.37.1 2024-03-16 14:51:49 +00:00
thejch
c942ce6dce renderer: add better multi monitor animations (#5126) 2024-03-16 14:49:34 +00:00
Vaxry
5e5d7e2abc renderer: fix non-reported sizes window box calculations
fixed #5129
2024-03-16 14:37:07 +00:00
128 changed files with 5148 additions and 1984 deletions

View File

@@ -13,7 +13,7 @@ body:
id: ver id: ver
attributes: attributes:
label: Hyprland Version label: Hyprland Version
description: "Paste here the output of `hyprctl version`. For hyprland after 0.34.0, paste `hyprctl systeminfo` instead." description: "Paste the output of `hyprctl systeminfo` here."
value: "<details> value: "<details>
<summary>System/Version info</summary> <summary>System/Version info</summary>
@@ -63,5 +63,5 @@ body:
description: | description: |
Anything that can help. Please always ATTACH and not paste them. Anything that can help. Please always ATTACH and not paste them.
Logs can be found in /tmp/hypr Logs can be found in /tmp/hypr
Crash reports are stored in ~/.hyprland or $XDG_CACHE_HOME/hyprland Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland

View File

@@ -53,6 +53,8 @@ runs:
xcb-util-errors \ xcb-util-errors \
xcb-util-renderutil \ xcb-util-renderutil \
xcb-util-wm \ xcb-util-wm \
xcb-util \
xcb-util-image \
libzip \ libzip \
librsvg librsvg

View File

@@ -32,7 +32,6 @@ jobs:
cp build/Hyprland hyprland/ cp build/Hyprland hyprland/
cp build/hyprctl/hyprctl hyprland/ cp build/hyprctl/hyprctl hyprland/
cp build/hyprpm/hyprpm hyprland/ cp build/hyprpm/hyprpm hyprland/
cp subprojects/wlroots/build/libwlroots.so.13032 hyprland/
cp build/Hyprland hyprland/ cp build/Hyprland hyprland/
cp -r example/ hyprland/ cp -r example/ hyprland/
cp -r assets/ hyprland/ cp -r assets/ hyprland/

View File

@@ -18,6 +18,7 @@ jobs:
- name: Generate version - name: Generate version
id: genversion id: genversion
run: | run: |
git fetch --unshallow || echo "failed unshallowing"
bash -c scripts/generateVersion.sh bash -c scripts/generateVersion.sh
mv scripts/generateVersion.sh scripts/generateVersion.sh.bak mv scripts/generateVersion.sh scripts/generateVersion.sh.bak

6
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "wlroots"]
path = subprojects/wlroots
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
[submodule "subprojects/hyprland-protocols"] [submodule "subprojects/hyprland-protocols"]
path = subprojects/hyprland-protocols path = subprojects/hyprland-protocols
url = https://github.com/hyprwm/hyprland-protocols url = https://github.com/hyprwm/hyprland-protocols
@@ -10,3 +7,6 @@
[submodule "subprojects/tracy"] [submodule "subprojects/tracy"]
path = subprojects/tracy path = subprojects/tracy
url = https://github.com/wolfpld/tracy url = https://github.com/wolfpld/tracy
[submodule "subprojects/wlroots-hyprland"]
path = subprojects/wlroots-hyprland
url = https://github.com/hyprwm/wlroots-hyprland

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.19) cmake_minimum_required(VERSION 3.27)
include(CheckIncludeFile) include(CheckIncludeFile)
# Get version # Get version
@@ -54,25 +54,22 @@ else()
endif() endif()
ExternalProject_Add( ExternalProject_Add(
wlroots wlroots-hyprland
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland
PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build 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>
CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$<IF:$<BOOL:${NO_XWAYLAND}>,disabled,enabled> -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none>
BUILD_COMMAND ninja -C build BUILD_COMMAND ninja -C build
BUILD_ALWAYS true BUILD_ALWAYS true
BUILD_IN_SOURCE true BUILD_IN_SOURCE true
BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032 BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a
INSTALL_COMMAND echo "wlroots: install not needed" INSTALL_COMMAND echo "wlroots-hyprland: install not needed"
) )
find_program(WaylandScanner NAMES wayland-scanner) find_package(PkgConfig REQUIRED)
pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner)
message(STATUS "Found WaylandScanner at ${WaylandScanner}") message(STATUS "Found WaylandScanner at ${WaylandScanner}")
execute_process( pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
COMMAND pkg-config --variable=pkgdatadir wayland-protocols
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE WAYLAND_PROTOCOLS_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
@@ -86,22 +83,34 @@ endif()
include_directories( include_directories(
. .
"src/" "src/"
"subprojects/wlroots/include/" "subprojects/wlroots-hyprland/include/"
"subprojects/wlroots/build/include/" "subprojects/wlroots-hyprland/build/include/"
"subprojects/udis86/" "subprojects/udis86/"
"protocols/") "protocols/")
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
add_compile_definitions(WLR_USE_UNSTABLE) 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) add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith)
add_link_options(-rdynamic)
set(CMAKE_ENABLE_EXPORTS TRUE) set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
message(STATUS "Checking deps...") message(STATUS "Checking deps...")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED) if(LEGACY_RENDERER)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2 hyprcursor) # we do not check for wlroots, as we provide it ourselves set(GLES_VERSION "GLES2")
else()
set(GLES_VERSION "GLES3")
endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(deps REQUIRED IMPORTED_TARGET
xkbcommon
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
)
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
@@ -112,7 +121,7 @@ if(USE_TRACY)
endif() endif()
add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
add_dependencies(Hyprland wlroots) add_dependencies(Hyprland wlroots-hyprland)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Setting debug flags") message(STATUS "Setting debug flags")
@@ -155,6 +164,12 @@ if(HAVE_LIBEXECINFO)
target_link_libraries(Hyprland execinfo) target_link_libraries(Hyprland execinfo)
endif() endif()
check_include_file("sys/timerfd.h" HAS_TIMERFD)
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
if(NOT HAS_TIMERFD AND epoll_FOUND)
target_link_libraries(Hyprland PkgConfig::epoll)
endif()
if(LEGACY_RENDERER) if(LEGACY_RENDERER)
message(STATUS "Using the legacy GLES2 renderer!") message(STATUS "Using the legacy GLES2 renderer!")
add_compile_definitions(LEGACY_RENDERER) add_compile_definitions(LEGACY_RENDERER)
@@ -165,8 +180,12 @@ if(NO_XWAYLAND)
add_compile_definitions(NO_XWAYLAND) add_compile_definitions(NO_XWAYLAND)
else() else()
message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...") message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
pkg_check_modules(xcbdep REQUIRED IMPORTED_TARGET xcb) pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh)
target_link_libraries(Hyprland PkgConfig::xcbdep) pkg_check_modules(xcb_errors IMPORTED_TARGET xcb-errors)
target_link_libraries(Hyprland PkgConfig::xdeps)
if(xcb_errors_FOUND)
target_link_libraries(Hyprland PkgConfig::xcb_errors)
endif()
endif() endif()
if(NO_SYSTEMD) if(NO_SYSTEMD)
@@ -221,7 +240,7 @@ function(protocol protoPath protoName external)
endfunction() endfunction()
target_link_libraries(Hyprland target_link_libraries(Hyprland
${CMAKE_SOURCE_DIR}/subprojects/wlroots/build/libwlroots.so.13032 # wlroots is provided by us ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a
OpenGL::EGL OpenGL::EGL
OpenGL::GL OpenGL::GL
Threads::Threads Threads::Threads

View File

@@ -1,6 +1,6 @@
BSD 3-Clause License BSD 3-Clause License
Copyright (c) 2022-2023, vaxerski Copyright (c) 2022-2024, vaxerski
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@@ -23,7 +23,7 @@ debug:
clear: clear:
rm -rf build rm -rf build
rm -f ./protocols/*-protocol.h ./protocols/*-protocol.c rm -f ./protocols/*-protocol.h ./protocols/*-protocol.c
rm -rf ./subprojects/wlroots/build rm -rf ./subprojects/wlroots-hyprland/build
all: all:
@if [[ "$EUID" = 0 ]]; then echo -en "Avoid running $(MAKE) all as sudo.\n"; fi @if [[ "$EUID" = 0 ]]; then echo -en "Avoid running $(MAKE) all as sudo.\n"; fi
@@ -36,15 +36,24 @@ install:
mkdir -p ${PREFIX}/share/wayland-sessions mkdir -p ${PREFIX}/share/wayland-sessions
mkdir -p ${PREFIX}/bin mkdir -p ${PREFIX}/bin
mkdir -p ${PREFIX}/share/hyprland
mkdir -p ${PREFIX}/share/bash-completion/completions
mkdir -p ${PREFIX}/share/fish/vendor_completions.d
mkdir -p ${PREFIX}/share/zsh/site-functions
cp -f ./build/Hyprland ${PREFIX}/bin cp -f ./build/Hyprland ${PREFIX}/bin
cp -f ./build/hyprctl/hyprctl ${PREFIX}/bin cp -f ./build/hyprctl/hyprctl ${PREFIX}/bin
cp -f ./build/hyprpm/hyprpm ${PREFIX}/bin cp -f ./build/hyprpm/hyprpm ${PREFIX}/bin
cp -f ./hyprctl/hyprctl.bash ${PREFIX}/share/bash-completion/completions/hyprctl
cp -f ./hyprctl/hyprctl.fish ${PREFIX}/share/fish/vendor_completions.d/hyprctl.fish
cp -f ./hyprctl/hyprctl.zsh ${PREFIX}/share/zsh/site-functions/_hyprctl
cp -f ./hyprpm/hyprpm.bash ${PREFIX}/share/bash-completion/completions/hyprpm
cp -f ./hyprpm/hyprpm.fish ${PREFIX}/share/fish/vendor_completions.d/hyprpm.fish
cp -f ./hyprpm/hyprpm.zsh ${PREFIX}/share/zsh/site-functions/_hyprpm
chmod 755 ${PREFIX}/bin/Hyprland chmod 755 ${PREFIX}/bin/Hyprland
chmod 755 ${PREFIX}/bin/hyprctl chmod 755 ${PREFIX}/bin/hyprctl
chmod 755 ${PREFIX}/bin/hyprpm chmod 755 ${PREFIX}/bin/hyprpm
cd ${PREFIX}/bin && ln -sf Hyprland hyprland cd ${PREFIX}/bin && ln -sf Hyprland hyprland
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
mkdir -p ${PREFIX}/share/hyprland
cp ./assets/wall* ${PREFIX}/share/hyprland cp ./assets/wall* ${PREFIX}/share/hyprland
mkdir -p ${PREFIX}/share/xdg-desktop-portal mkdir -p ${PREFIX}/share/xdg-desktop-portal
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
@@ -52,9 +61,6 @@ install:
mkdir -p ${PREFIX}/share/man/man1 mkdir -p ${PREFIX}/share/man/man1
install -m644 ./docs/*.1 ${PREFIX}/share/man/man1 install -m644 ./docs/*.1 ${PREFIX}/share/man/man1
mkdir -p ${PREFIX}/lib/
cp ./subprojects/wlroots/build/libwlroots.so.13032 ${PREFIX}/lib/
$(MAKE) installheaders $(MAKE) installheaders
uninstall: uninstall:
@@ -63,10 +69,15 @@ uninstall:
rm -f ${PREFIX}/bin/hyprland rm -f ${PREFIX}/bin/hyprland
rm -f ${PREFIX}/bin/hyprctl rm -f ${PREFIX}/bin/hyprctl
rm -f ${PREFIX}/bin/hyprpm rm -f ${PREFIX}/bin/hyprpm
rm -f ${PREFIX}/lib/libwlroots.so.13032
rm -rf ${PREFIX}/share/hyprland rm -rf ${PREFIX}/share/hyprland
rm -f ${PREFIX}/share/man/man1/Hyprland.1 rm -f ${PREFIX}/share/man/man1/Hyprland.1
rm -f ${PREFIX}/share/man/man1/hyprctl.1 rm -f ${PREFIX}/share/man/man1/hyprctl.1
rm -f ${PREFIX}/share/bash-completion/completions/hyprctl
rm -f ${PREFIX}/share/fish/vendor_completions.d/hyprctl.fish
rm -f ${PREFIX}/share/zsh/site-functions/_hyprctl
rm -f ${PREFIX}/share/bash-completion/completions/hyprpm
rm -f ${PREFIX}/share/fish/vendor_completions.d/hyprpm.fish
rm -f ${PREFIX}/share/zsh/site-functions/_hyprpm
pluginenv: pluginenv:
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n" @echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
@@ -75,14 +86,15 @@ pluginenv:
installheaders: installheaders:
@if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi @if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
rm -fr ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland/protocols mkdir -p ${PREFIX}/include/hyprland/protocols
mkdir -p ${PREFIX}/include/hyprland/wlroots mkdir -p ${PREFIX}/include/hyprland/wlroots-hyprland
mkdir -p ${PREFIX}/share/pkgconfig mkdir -p ${PREFIX}/share/pkgconfig
find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
cd subprojects/wlroots/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots && cd ../../.. cd subprojects/wlroots-hyprland/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots-hyprland && cd ../../..
cd subprojects/wlroots/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots && cd ../../../.. cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots-hyprland && cd ../../../..
cp ./protocols/*-protocol.h ${PREFIX}/include/hyprland/protocols cp ./protocols/*-protocol.h ${PREFIX}/include/hyprland/protocols
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
@@ -115,6 +127,10 @@ asan:
rm -rf ./wayland rm -rf ./wayland
git reset --hard git reset --hard
@echo -en "If you want to apply a patch, input its path (leave empty for none):\n"
@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 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 .. cd wayland && patch -p1 < ../scripts/waylandStatic.diff && meson setup build --buildtype=debug -Db_sanitize=address -Ddocumentation=false && ninja -C build && cd ..
cp ./wayland/build/src/libwayland-server.a . cp ./wayland/build/src/libwayland-server.a .

View File

@@ -130,7 +130,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg [Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
[Preview A]: https://i.ibb.co/C1yTb0r/falf.png [Preview A]: https://i.ibb.co/C1yTb0r/falf.png
[Preview B]: https://cdn.discordapp.com/attachments/1091569872535814185/1107675866101723277/screenshot-summer.png [Preview B]: https://linfindel.github.io/cdn/hyprland-preview-b.png
[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png [Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png

91
flake.lock generated
View File

@@ -2,7 +2,9 @@
"nodes": { "nodes": {
"hyprcursor": { "hyprcursor": {
"inputs": { "inputs": {
"hyprlang": "hyprlang", "hyprlang": [
"hyprlang"
],
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
@@ -11,11 +13,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1710257359, "lastModified": 1713214463,
"narHash": "sha256-43re5pzE/cswFAgw92/ugsB3+d5ufDaCcLtl9ztKfBo=", "narHash": "sha256-zAOOjqHAbccCRgJSuvTCA0FNLqKswN63LgVo43R7pxw=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprcursor", "repo": "hyprcursor",
"rev": "1761f6cefd77f4fcd2039d930c88d6716ddc4974", "rev": "0a53b9957f0b17f1a0036b25198f569969ad43a0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -48,28 +50,6 @@
} }
}, },
"hyprlang": { "hyprlang": {
"inputs": {
"nixpkgs": [
"hyprcursor",
"nixpkgs"
],
"systems": "systems"
},
"locked": {
"lastModified": 1709914708,
"narHash": "sha256-bR4o3mynoTa1Wi4ZTjbnsZ6iqVcPGriXp56bZh5UFTk=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "a685493fdbeec01ca8ccdf1f3655c044a8ce2fe2",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprlang",
"type": "github"
}
},
"hyprlang_2": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
@@ -79,11 +59,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1709914708, "lastModified": 1713121246,
"narHash": "sha256-bR4o3mynoTa1Wi4ZTjbnsZ6iqVcPGriXp56bZh5UFTk=", "narHash": "sha256-502X0Q0fhN6tJK7iEUA8CghONKSatW/Mqj4Wappd++0=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "hyprlang", "repo": "hyprlang",
"rev": "a685493fdbeec01ca8ccdf1f3655c044a8ce2fe2", "rev": "78fcaa27ae9e1d782faa3ff06c8ea55ddce63706",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -94,11 +74,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1710272261, "lastModified": 1712963716,
"narHash": "sha256-g0bDwXFmTE7uGDOs9HcJsfLFhH7fOsASbAuOzDC+fhQ=", "narHash": "sha256-WKm9CvgCldeIVvRz87iOMi8CFVB1apJlkUT4GGvA0iM=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0ad13a6833440b8e238947e47bea7f11071dc2b2", "rev": "cfd6b5fc90b15709b780a5a1619695a88505a176",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -112,9 +92,9 @@
"inputs": { "inputs": {
"hyprcursor": "hyprcursor", "hyprcursor": "hyprcursor",
"hyprland-protocols": "hyprland-protocols", "hyprland-protocols": "hyprland-protocols",
"hyprlang": "hyprlang_2", "hyprlang": "hyprlang",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"systems": "systems_2", "systems": "systems",
"wlroots": "wlroots", "wlroots": "wlroots",
"xdph": "xdph" "xdph": "xdph"
} }
@@ -134,38 +114,21 @@
"type": "github" "type": "github"
} }
}, },
"systems_2": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
},
"wlroots": { "wlroots": {
"flake": false, "flake": false,
"locked": { "locked": {
"host": "gitlab.freedesktop.org", "lastModified": 1713124002,
"lastModified": 1709983277, "narHash": "sha256-vPeZCY+sdiGsz4fl3AVVujfyZyQBz6+vZdkUE4hQ+HI=",
"narHash": "sha256-wXWIJLd4F2JZeMaihWVDW/yYXCLEC8OpeNJZg9a9ly8=", "owner": "hyprwm",
"owner": "wlroots", "repo": "wlroots-hyprland",
"repo": "wlroots", "rev": "611a4f24cd2384378f6e500253983107c6656c64",
"rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b", "type": "github"
"type": "gitlab"
}, },
"original": { "original": {
"host": "gitlab.freedesktop.org", "owner": "hyprwm",
"owner": "wlroots", "repo": "wlroots-hyprland",
"repo": "wlroots", "rev": "611a4f24cd2384378f6e500253983107c6656c64",
"rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b", "type": "github"
"type": "gitlab"
} }
}, },
"xdph": { "xdph": {
@@ -184,11 +147,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1709299639, "lastModified": 1713214484,
"narHash": "sha256-jYqJM5khksLIbqSxCLUUcqEgI+O2LdlSlcMEBs39CAU=", "narHash": "sha256-h1bSIsDuPk1FGgvTuSHJyiU2Glu7oAyoPMJutKZmLQ8=",
"owner": "hyprwm", "owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland", "repo": "xdg-desktop-portal-hyprland",
"rev": "2d2fb547178ec025da643db57d40a971507b82fe", "rev": "bb44921534a9cee9635304fdb876c1b3ec3a8f61",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -8,11 +8,10 @@
systems.url = "github:nix-systems/default-linux"; systems.url = "github:nix-systems/default-linux";
wlroots = { wlroots = {
type = "gitlab"; type = "github";
host = "gitlab.freedesktop.org"; owner = "hyprwm";
owner = "wlroots"; repo = "wlroots-hyprland";
repo = "wlroots"; rev = "611a4f24cd2384378f6e500253983107c6656c64";
rev = "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b";
flake = false; flake = false;
}; };
@@ -20,6 +19,7 @@
url = "github:hyprwm/hyprcursor"; url = "github:hyprwm/hyprcursor";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems"; inputs.systems.follows = "systems";
inputs.hyprlang.follows = "hyprlang";
}; };
hyprland-protocols = { hyprland-protocols = {

158
hyprctl/Strings.hpp Normal file
View File

@@ -0,0 +1,158 @@
#pragma once
const std::string_view USAGE = R"#(usage: hyprctl [flags] <command> [args...|--help]
commands:
activewindow Gets the active window name and its properties
activeworkspace Gets the active workspace and its properties
animations Gets the current config'd info about animations
and beziers
binds Lists all registered binds
clients Lists all windows with their properties
configerrors Lists all current config parsing errors
cursorpos Gets the current cursor position in global layout
coordinates
decorations <window_regex> Lists all decorations and their info
devices Lists all connected keyboards and mice
dismissnotify [amount] Dismisses all or up to AMOUNT notifications
dispatch <dispatcher> [args] Issue a dispatch to call a keybind
dispatcher with arguments
getoption <option> Gets the config option status (values)
globalshortcuts Lists all global shortcuts
hyprpaper ... Issue a hyprpaper request
instances Lists all running instances of Hyprland with
their info
keyword <name> <value> Issue a keyword to call a config keyword
dynamically
kill Issue a kill to get into a kill mode, where you can
kill an app by clicking on it. You can exit it
with ESCAPE
layers Lists all the surface layers
layouts Lists all layouts available (including plugin'd ones)
monitors Lists active outputs with their properties,
'monitors all' lists active and inactive outputs
notify ... Sends a notification using the built-in Hyprland
notification system
output ... Allows you to add and remove fake outputs to your
preferred backend
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
setcursor <theme> <size> Sets the cursor theme and reloads the cursor
manager
seterror <color> <message...> Sets the hyprctl error string. Color has
the same format as in colors in config. Will reset
when Hyprland's config is reloaded
setprop ... Sets a window property
splash Get the current splash
switchxkblayout ... Sets the xkb layout index for a keyboard
systeminfo Get system info
version Prints the hyprland version, meaning flags, commit
and branch of build.
workspacerules Lists all workspace rules
workspaces Lists all workspaces with their properties
flags:
-j Output in JSON
-r Refresh state after issuing command (e.g. for
updating variables)
--batch Execute a batch of commands, separated by ';'
--instance (-i) use a specific instance. Can be either signature or
index in hyprctl instances (0, 1, etc)
--help:
Can be used to print command's arguments that did not fit into this page
(three dots))#";
const std::string_view HYPRPAPER_HELP = R"#(usage: hyprctl [flags] hyprpaper <request>
requests:
listactive Lists all active images
listloaded Lists all loaded images
preload <path> Preloads image
unload <path> Unloads image. Pass 'all' as path to unload all images
wallpaper Issue a wallpaper to call a config wallpaper dynamically
flags:
See 'hyprctl --help')#";
const std::string_view NOTIFY_HELP = R"#(usage: hyprctl [flags] notify <icon> <time_ms> <color> <message...>
icon:
Integer of value:
0 Warning
1 Info
2 Hint
3 Error
4 Confused
5 Ok
6 or -1 No icon
time_ms:
Time to display notification in milliseconds
color:
Notification color. Format is the same as for colors in hyprland.conf. Use
0 for default color for icon
message:
Notification message
flags:
See 'hyprctl --help')#";
const std::string_view OUTPUT_HELP = R"#(usage: hyprctl [flags] output <create <backend> | remove <name>>
create <backend>:
Creates new virtual output. Possible values for backend: wayland, x11,
headless or auto.
remove <name>:
Removes virtual output. Pass the output's name, as found in
'hyprctl monitors'
flags:
See 'hyprctl --help')#";
const std::string_view PLUGIN_HELP = R"#(usage: hyprctl [flags] plugin <request>
requests:
load <path> Loads a plugin. Path must be absolute
unload <path> Unloads a plugin. Path must be absolute
list Lists all loaded plugins
flags:
See 'hyprctl --help')#";
const std::string_view SETPROP_HELP = R"#(usage: hyprctl [flags] setprop <regex> <property> <value> [lock]
regex:
Regular expression by which a window will be searched
property:
See https://wiki.hyprland.org/Configuring/Using-hyprctl/#setprop for list
of properties
value:
Property value
lock:
Optional argument. If lock is not added, will be unlocked. Locking means a
dynamic windowrule cannot override this setting.
flags:
See 'hyprctl --help')#";
const std::string_view SWITCHXKBLAYOUT_HELP = R"#(usage: [flags] switchxkblayout <device> <cmd>
device:
You can find the device using 'hyprctl devices' command
cmd:
'next' for next, 'prev' for previous, or ID for a specific one. IDs are
assigned based on their order in config file (keyboard_layout),
starting from 0
flags:
See 'hyprctl --help')#";

127
hyprctl/hyprctl.bash Normal file
View File

@@ -0,0 +1,127 @@
_hyprctl_cmd_2 () {
hyprctl monitors | grep Monitor | awk '{ print $2 }'
}
_hyprctl_cmd_1 () {
hyprpm list | grep "Plugin" | awk '{print $4}'
}
_hyprctl_cmd_0 () {
hyprctl clients | grep class | awk '{print $2}'
}
_hyprctl_cmd_3 () {
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
}
_hyprctl () {
if [[ $(type -t _get_comp_words_by_ref) != function ]]; then
echo _get_comp_words_by_ref: function not defined. Make sure the bash-completions system package is installed
return 1
fi
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" "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" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
declare -A literal_transitions
literal_transitions[0]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [108]=5 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [96]=5 [97]=2 [27]=2 [28]=14 [100]=2 [102]=5)"
literal_transitions[3]="([72]=18 [13]=2 [32]=18 [54]=18 [55]=18 [89]=18 [104]=2 [120]=2 [76]=1 [16]=2 [123]=18 [3]=1 [5]=2 [63]=18 [127]=2 [129]=18 [80]=18 [130]=18 [83]=18 [31]=18 [48]=2 [12]=2 [85]=18 [10]=18 [86]=18 [137]=18)"
literal_transitions[7]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [97]=2 [27]=2 [28]=14 [100]=2)"
literal_transitions[8]="([128]=2 [131]=2 [0]=2 [73]=2 [35]=2 [106]=2 [37]=2 [107]=2 [4]=2 [78]=2 [39]=2 [79]=2 [110]=2 [6]=2 [41]=2 [42]=2 [81]=2 [82]=2 [46]=2 [47]=2 [9]=2 [109]=2 [50]=2 [52]=2 [11]=2 [115]=2 [87]=2 [49]=2 [56]=2 [90]=2 [57]=2 [91]=2 [92]=2 [60]=2 [61]=2 [125]=2 [93]=2 [62]=2 [20]=2 [95]=2 [22]=2 [23]=2 [64]=2 [65]=2 [24]=2 [132]=2 [26]=2 [68]=2 [98]=2 [69]=2 [29]=2 [136]=2 [70]=2 [99]=2)"
literal_transitions[9]="([114]=15 [111]=16)"
literal_transitions[11]="([101]=2)"
literal_transitions[13]="([21]=1 [116]=1 [30]=1 [135]=1 [118]=1 [43]=1 [71]=1)"
literal_transitions[14]="([38]=2)"
literal_transitions[15]="([8]=2 [66]=2 [14]=2 [133]=2)"
literal_transitions[17]="([75]=19)"
literal_transitions[18]="([18]=2 [7]=2)"
literal_transitions[19]="([34]=5 [44]=5)"
literal_transitions[20]="([134]=2 [94]=2)"
declare -A match_anything_transitions
match_anything_transitions=([1]=2 [0]=7 [6]=2 [20]=2 [10]=2 [2]=17 [7]=7 [12]=2 [14]=17 [16]=2 [4]=20 [11]=17)
declare -A subword_transitions
local state=0
local word_index=1
while [[ $word_index -lt $cword ]]; do
local word=${words[$word_index]}
if [[ -v "literal_transitions[$state]" ]]; then
declare -A state_transitions
eval "state_transitions=${literal_transitions[$state]}"
local word_matched=0
for literal_id in $(seq 0 $((${#literals[@]} - 1))); do
if [[ ${literals[$literal_id]} = "$word" ]]; then
if [[ -v "state_transitions[$literal_id]" ]]; then
state=${state_transitions[$literal_id]}
word_index=$((word_index + 1))
word_matched=1
break
fi
fi
done
if [[ $word_matched -ne 0 ]]; then
continue
fi
fi
if [[ -v "match_anything_transitions[$state]" ]]; then
state=${match_anything_transitions[$state]}
word_index=$((word_index + 1))
continue
fi
return 1
done
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
eval "state_transitions=$state_transitions_initializer"
for literal_id in "${!state_transitions[@]}"; do
local literal="${literals[$literal_id]}"
if [[ $literal = "${prefix}"* ]]; then
local completion=${literal#"$superfluous_prefix"}
COMPREPLY+=("$completion ")
fi
done
fi
declare -A commands
commands=([16]=2 [4]=3 [12]=1 [10]=0)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
local completions=()
mapfile -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1)
for item in "${completions[@]}"; do
if [[ $item = "${prefix}"* ]]; then
COMPREPLY+=("$item")
fi
done
fi
return 0
}
complete -o nospace -F _hyprctl hyprctl

216
hyprctl/hyprctl.fish Normal file
View File

@@ -0,0 +1,216 @@
function _hyprctl_3
set 1 $argv[1]
hyprctl monitors | grep Monitor | awk '{ print $2 }'
end
function _hyprctl_2
set 1 $argv[1]
hyprpm list | grep "Plugin" | awk '{print $4}'
end
function _hyprctl_1
set 1 $argv[1]
hyprctl clients | grep class | awk '{print $2}'
end
function _hyprctl_4
set 1 $argv[1]
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
end
function _hyprctl
set COMP_LINE (commandline --cut-at-cursor)
set COMP_WORDS
echo $COMP_LINE | read --tokenize --array COMP_WORDS
if string match --quiet --regex '.*\s$' $COMP_LINE
set COMP_CWORD (math (count $COMP_WORDS) + 1)
else
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" "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" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow"
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] "Toggle the current window's floating state"
set descriptions[37] "Get the list of defined workspace rules"
set descriptions[38] "Move the focused window to a workspace"
set descriptions[40] "Temporarily enable or disable binds:ignore_group_lock"
set descriptions[41] "List all workspaces with their properties"
set descriptions[42] "Swap the active window with the next or previous in a group"
set descriptions[43] "Close a specified window"
set descriptions[44] "WARNING"
set descriptions[45] "Specify the Hyprland instance"
set descriptions[46] "List all registered binds"
set descriptions[47] "Move the active window in a direction or to a monitor"
set descriptions[48] "Change the split ratio"
set descriptions[50] "Prohibit the active window from becoming or being inserted into group"
set descriptions[51] "Change the workspace"
set descriptions[52] "List all current config parsing errors"
set descriptions[53] "Toggle the current active window into a group"
set descriptions[54] "Get the config option status (values)"
set descriptions[57] "Close the active window"
set descriptions[58] "Pass the key to a specified window"
set descriptions[59] "List all decorations and their info"
set descriptions[60] "List all connected keyboards and mice"
set descriptions[61] "Switch focus from current to previously focused window"
set descriptions[62] "Change the current mapping group"
set descriptions[63] "Execute a Global Shortcut using the GlobalShortcuts portal"
set descriptions[65] "Force the renderer to reload all resources and outputs"
set descriptions[66] "Move a selected window"
set descriptions[68] "Print the Hyprland version: flags, commit and branch of build"
set descriptions[69] "Set all monitors' DPMS status"
set descriptions[70] "Resize the active window"
set descriptions[71] "Move the active window into a group"
set descriptions[72] "OK"
set descriptions[74] "Set the current window's floating state to true"
set descriptions[75] "Print tail of the log"
set descriptions[78] "List all layouts available (including plugin ones)"
set descriptions[79] "Move a workspace to a monitor"
set descriptions[80] "Execute a shell command"
set descriptions[82] "Modify the window stack order of the active or specified window"
set descriptions[83] "Toggle the focused window's internal fullscreen state"
set descriptions[85] "Issue a keyword to call a config keyword dynamically"
set descriptions[88] "Pin a window"
set descriptions[89] "Allows adding/removing fake outputs to a specific backend"
set descriptions[91] "Toggle a special workspace on/off"
set descriptions[92] "Toggle the focused window's fullscreen state"
set descriptions[93] "Toggle the current window to always be opaque"
set descriptions[94] "Focus the requested workspace"
set descriptions[96] "Switch to the next window in a group"
set descriptions[97] "Output in JSON format"
set descriptions[98] "List all running Hyprland instances and their info"
set descriptions[99] "Execute a raw shell command"
set descriptions[100] "Exit the compositor with no questions asked"
set descriptions[101] "List all windows with their properties"
set descriptions[103] "Execute a batch of commands separated by ;"
set descriptions[104] "Dismiss all or up to amount of notifications"
set descriptions[106] "Set the xkb layout index for a keyboard"
set descriptions[107] "Move window doesnt switch to the workspace"
set descriptions[108] "Behave as moveintogroup"
set descriptions[109] "Refresh state after issuing the command"
set descriptions[110] "Move the focus in a direction"
set descriptions[111] "Focus the urgent window or the last window"
set descriptions[113] "Get the active workspace name and its properties"
set descriptions[114] "Issue a dispatch to call a keybind dispatcher with an arg"
set descriptions[116] "Center the active window"
set descriptions[117] "HINT"
set descriptions[118] "Interact with hyprpaper if present"
set descriptions[119] "No Icon"
set descriptions[120] "Force reload the config"
set descriptions[122] "Print system info"
set descriptions[123] "Interact with a plugin"
set descriptions[125] "Get the active window name and its properties"
set descriptions[126] "Swap the active workspaces between two monitors"
set descriptions[127] "Print the current random splash"
set descriptions[129] "Lock the focused group"
set descriptions[132] "Lock the groups"
set descriptions[133] "Move the cursor to the corner of the active window"
set descriptions[136] "INFO"
set descriptions[137] "Resize a selected window"
set --local literal_transitions
set literal_transitions[1] "set inputs 104 75 34 2 3 78 106 37 109 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 97 98 28 29 101 103; set tos 2 3 4 3 3 3 5 3 6 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 6 3 3 15 3 6"
set literal_transitions[4] "set inputs 73 14 33 55 56 90 105 121 77 17 124 4 6 64 128 130 81 131 84 32 49 13 86 11 87 138; set tos 19 3 19 19 19 19 3 3 2 3 19 2 3 19 3 19 19 19 19 19 3 3 19 19 19 19"
set literal_transitions[8] "set inputs 104 75 34 2 3 78 106 37 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 98 28 29 101; set tos 2 3 4 3 3 3 5 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 129 132 1 74 36 107 38 108 5 79 40 80 111 7 42 43 82 83 47 48 10 110 51 53 12 116 88 50 57 91 58 92 93 61 62 126 94 63 21 96 23 24 65 66 25 133 27 69 99 70 30 137 71 100; 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"
set literal_transitions[10] "set inputs 115 112; set tos 16 17"
set literal_transitions[12] "set inputs 102; set tos 3"
set literal_transitions[14] "set inputs 22 117 31 136 119 44 72; set tos 2 2 2 2 2 2 2"
set literal_transitions[15] "set inputs 39; set tos 3"
set literal_transitions[16] "set inputs 9 67 15 134; set tos 3 3 3 3"
set literal_transitions[18] "set inputs 76; set tos 20"
set literal_transitions[19] "set inputs 19 8; set tos 3 3"
set literal_transitions[20] "set inputs 35 45; set tos 6 6"
set literal_transitions[21] "set inputs 135 95; set tos 3 3"
set --local match_anything_transitions_from 2 1 7 21 11 3 8 13 15 17 5 12
set --local match_anything_transitions_to 3 8 3 3 3 18 8 3 18 3 21 18
set --local state 1
set --local word_index 2
while test $word_index -lt $COMP_CWORD
set --local -- word $COMP_WORDS[$word_index]
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
set --local --erase inputs
set --local --erase tos
eval $literal_transitions[$state]
if contains -- $word $literals
set --local 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 state $tos[$index]
set word_index (math $word_index + 1)
set literal_matched 1
break
end
end
if test $literal_matched -ne 0
continue
end
end
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 state $match_anything_transitions_to[$index]
set word_index (math $word_index + 1)
continue
end
return 1
end
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
set --local --erase inputs
set --local --erase tos
eval $literal_transitions[$state]
for literal_id in $inputs
if test -n $descriptions[$literal_id]
printf '%s\t%s\n' $literals[$literal_id] $descriptions[$literal_id]
else
printf '%s\n' $literals[$literal_id]
end
end
end
set command_states 17 5 13 11
set command_ids 3 4 2 1
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
$function_name "$COMP_WORDS[$COMP_CWORD]"
end
return 0
end
complete --command hyprctl --no-files --arguments "(_hyprctl)"

148
hyprctl/hyprctl.usage Normal file
View File

@@ -0,0 +1,148 @@
# This is a file feeded to complgen to generate bash/fish/zsh completions
# Repo: https://github.com/adaszko/complgen
# Generate completion scripts: "complgen aot --bash-script hyprctl.bash --fish-script hyprctl.fish --zsh-script hyprctl.zsh ./hyprctl.usage"
hyprctl [<OPTIONS>]... <ARGUMENTS>
<OPTIONS> ::= (-i | --instance) "Specify the Hyprland instance"
| (-j) "Output in JSON format"
| (-r) "Refresh state after issuing the command"
| (--batch) "Execute a batch of commands separated by ;"
;
<WINDOWS> ::= {{{ hyprctl clients | grep class | awk '{print $2}' }}};
<AVAILABLE_PLUGINS> ::= {{{ hyprpm list | grep "Plugin" | awk '{print $4}' }}};
<MONITORS> ::= {{{ hyprctl monitors | grep Monitor | awk '{ print $2 }' }}};
<KEYBOARDS> ::= {{{ hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' }}};
<NOTIFICATION_TYPES> ::= (0) "WARNING"
| (1) "INFO"
| (2) "HINT"
| (3) "ERROR"
| (4) "CONFUSED"
| (5) "OK"
| (-1) "No Icon"
;
<PROPS> ::= (animationstyle)
| (rounding <NUM>)
| (bordersize <NUM>)
| (forcenoblur (0 | 1))
| (forceopaque (0 | 1))
| (forceopaqueoverriden (0 | 1))
| (forceallowsinput (0 | 1))
| (forcenoanims (0 | 1))
| (forcenoborder (0 | 1))
| (forcenodim (0 | 1))
| (forcenoshadow (0 | 1))
| (nofocus (0 | 1))
| (windowdancecompat (0 | 1))
| (nomaxsize (0 | 1))
| (minsize)
| (maxsize)
| (dimaround (0 | 1))
| (keepaspectratio (0 | 1))
| (alphaoverride (0 | 1))
| (alpha)
| (alphainactiveoverride (0 | 1))
| (alphainactive)
| (alphafullscreenoverride (0 | 1))
| (alphafullscreen)
| (activebordercolor)
| (inactivebordercolor)
;
<ARGUMENTS> ::= (activewindow) "Get the active window name and its properties"
| (activeworkspace) "Get the active workspace name and its properties"
| (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"
| (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) ""
| (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"
| (kill) "Get into a kill mode, where you can kill an app by clicking on it"
| (layers) "List the layers"
| (layouts) "List all layouts available (including plugin ones)"
| (monitors [all]) "List active outputs with their properties"
| (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"
| (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"
| (splash) "Print the current random splash"
| (switchxkblayout <KEYBOARDS> (next | prev | <NUM>)) "Set the xkb layout index for a keyboard"
| (systeminfo) "Print system info"
| (version) "Print the Hyprland version: flags, commit and branch of build"
| (workspacerules) "Get the list of defined workspace rules"
| (workspaces) "List all workspaces with their properties"
;
<DISPATCHERS> ::= (exec) "Execute a shell command"
| (execr) "Execute a raw shell command"
| (pass) "Pass the key to a specified window"
| (killactive) "Close the active window"
| (closewindow) "Close a specified window"
| (workspace) "Change the workspace"
| (movetoworkspace) "Move the focused window to a workspace"
| (movetoworkspacesilent) "Move window doesnt switch to the workspace"
| (togglefloating) "Toggle the current window's floating state"
| (setfloating) "Set the current window's floating state to true"
| (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"
| (dpms) "Set all monitors' DPMS status"
| (pin) "Pin a window"
| (movefocus) "Move the focus in a direction"
| (movewindow) "Move the active window in a direction or to a monitor"
| (swapwindow) "Swap the active window with another window"
| (centerwindow) "Center the active window"
| (resizeactive) "Resize the active window"
| (moveactive) "Move the active window"
| (resizewindowpixel) "Resize a selected window"
| (movewindowpixel) "Move a selected window"
| (cyclenext) "Focus the next window on a workspace"
| (swapnext) "Swap the focused window with the next window"
| (focuswindow) "Focus the first window matching"
| (focusmonitor) "Focus a monitor"
| (splitratio) "Change the split ratio"
| (toggleopaque) "Toggle the current window to always be opaque"
| (movecursortocorner) "Move the cursor to the corner of the active window"
| (movecursor) "Move the cursor to a specified position"
| (renameworkspace) "Rename a workspace"
| (exit) "Exit the compositor with no questions asked"
| (forcerendererreload) "Force the renderer to reload all resources and outputs"
| (movecurrentworkspacetomonitor) "Move the active workspace to a monitor"
| (focusworkspaceoncurrentmonitor) "Focus the requested workspace"
| (moveworkspacetomonitor) "Move a workspace to a monitor"
| (swapactiveworkspaces) "Swap the active workspaces between two monitors"
| (alterzorder) "Modify the window stack order of the active or specified window"
| (togglespecialworkspace) "Toggle a special workspace on/off"
| (focusurgentorlast) "Focus the urgent window or the last window"
| (togglegroup) "Toggle the current active window into a group"
| (changegroupactive) "Switch to the next window in a group"
| (focuscurrentorlast) "Switch focus from current to previously focused window"
| (lockgroups) "Lock the groups"
| (lockactivegroup) "Lock the focused group"
| (moveintogroup) "Move the active window into a group"
| (moveoutofgroup) "Move the active window out of a group"
| (movewindoworgroup) "Behave as moveintogroup"
| (movegroupwindow) "Swap the active window with the next or previous in a group"
| (denywindowfromgroup) "Prohibit the active window from becoming or being inserted into group"
| (setignoregrouplock) "Temporarily enable or disable binds:ignore_group_lock"
| (global) "Execute a Global Shortcut using the GlobalShortcuts portal"
| (submap) "Change the current mapping group"
;

251
hyprctl/hyprctl.zsh Normal file
View File

@@ -0,0 +1,251 @@
#compdef hyprctl
_hyprctl_cmd_2 () {
hyprctl monitors | grep Monitor | awk '{ print $2 }'
}
_hyprctl_cmd_1 () {
hyprpm list | grep "Plugin" | awk '{print $4}'
}
_hyprctl_cmd_0 () {
hyprctl clients | grep class | awk '{print $2}'
}
_hyprctl_cmd_3 () {
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
}
_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" "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" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
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]="Toggle the current window's floating state"
descriptions[37]="Get the list of defined workspace rules"
descriptions[38]="Move the focused window to a workspace"
descriptions[40]="Temporarily enable or disable binds:ignore_group_lock"
descriptions[41]="List all workspaces with their properties"
descriptions[42]="Swap the active window with the next or previous in a group"
descriptions[43]="Close a specified window"
descriptions[44]="WARNING"
descriptions[45]="Specify the Hyprland instance"
descriptions[46]="List all registered binds"
descriptions[47]="Move the active window in a direction or to a monitor"
descriptions[48]="Change the split ratio"
descriptions[50]="Prohibit the active window from becoming or being inserted into group"
descriptions[51]="Change the workspace"
descriptions[52]="List all current config parsing errors"
descriptions[53]="Toggle the current active window into a group"
descriptions[54]="Get the config option status (values)"
descriptions[57]="Close the active window"
descriptions[58]="Pass the key to a specified window"
descriptions[59]="List all decorations and their info"
descriptions[60]="List all connected keyboards and mice"
descriptions[61]="Switch focus from current to previously focused window"
descriptions[62]="Change the current mapping group"
descriptions[63]="Execute a Global Shortcut using the GlobalShortcuts portal"
descriptions[65]="Force the renderer to reload all resources and outputs"
descriptions[66]="Move a selected window"
descriptions[68]="Print the Hyprland version: flags, commit and branch of build"
descriptions[69]="Set all monitors' DPMS status"
descriptions[70]="Resize the active window"
descriptions[71]="Move the active window into a group"
descriptions[72]="OK"
descriptions[74]="Set the current window's floating state to true"
descriptions[75]="Print tail of the log"
descriptions[78]="List all layouts available (including plugin ones)"
descriptions[79]="Move a workspace to a monitor"
descriptions[80]="Execute a shell command"
descriptions[82]="Modify the window stack order of the active or specified window"
descriptions[83]="Toggle the focused window's internal fullscreen state"
descriptions[85]="Issue a keyword to call a config keyword dynamically"
descriptions[88]="Pin a window"
descriptions[89]="Allows adding/removing fake outputs to a specific backend"
descriptions[91]="Toggle a special workspace on/off"
descriptions[92]="Toggle the focused window's fullscreen state"
descriptions[93]="Toggle the current window to always be opaque"
descriptions[94]="Focus the requested workspace"
descriptions[96]="Switch to the next window in a group"
descriptions[97]="Output in JSON format"
descriptions[98]="List all running Hyprland instances and their info"
descriptions[99]="Execute a raw shell command"
descriptions[100]="Exit the compositor with no questions asked"
descriptions[101]="List all windows with their properties"
descriptions[103]="Execute a batch of commands separated by ;"
descriptions[104]="Dismiss all or up to amount of notifications"
descriptions[106]="Set the xkb layout index for a keyboard"
descriptions[107]="Move window doesnt switch to the workspace"
descriptions[108]="Behave as moveintogroup"
descriptions[109]="Refresh state after issuing the command"
descriptions[110]="Move the focus in a direction"
descriptions[111]="Focus the urgent window or the last window"
descriptions[113]="Get the active workspace name and its properties"
descriptions[114]="Issue a dispatch to call a keybind dispatcher with an arg"
descriptions[116]="Center the active window"
descriptions[117]="HINT"
descriptions[118]="Interact with hyprpaper if present"
descriptions[119]="No Icon"
descriptions[120]="Force reload the config"
descriptions[122]="Print system info"
descriptions[123]="Interact with a plugin"
descriptions[125]="Get the active window name and its properties"
descriptions[126]="Swap the active workspaces between two monitors"
descriptions[127]="Print the current random splash"
descriptions[129]="Lock the focused group"
descriptions[132]="Lock the groups"
descriptions[133]="Move the cursor to the corner of the active window"
descriptions[136]="INFO"
descriptions[137]="Resize a selected window"
local -A literal_transitions
literal_transitions[1]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [109]=6 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [97]=6 [98]=3 [28]=3 [29]=15 [101]=3 [103]=6)"
literal_transitions[4]="([73]=19 [14]=3 [33]=19 [55]=19 [56]=19 [90]=19 [105]=3 [121]=3 [77]=2 [17]=3 [124]=19 [4]=2 [6]=3 [64]=19 [128]=3 [130]=19 [81]=19 [131]=19 [84]=19 [32]=19 [49]=3 [13]=3 [86]=19 [11]=19 [87]=19 [138]=19)"
literal_transitions[8]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [98]=3 [28]=3 [29]=15 [101]=3)"
literal_transitions[9]="([129]=3 [132]=3 [1]=3 [74]=3 [36]=3 [107]=3 [38]=3 [108]=3 [5]=3 [79]=3 [40]=3 [80]=3 [111]=3 [7]=3 [42]=3 [43]=3 [82]=3 [83]=3 [47]=3 [48]=3 [10]=3 [110]=3 [51]=3 [53]=3 [12]=3 [116]=3 [88]=3 [50]=3 [57]=3 [91]=3 [58]=3 [92]=3 [93]=3 [61]=3 [62]=3 [126]=3 [94]=3 [63]=3 [21]=3 [96]=3 [23]=3 [24]=3 [65]=3 [66]=3 [25]=3 [133]=3 [27]=3 [69]=3 [99]=3 [70]=3 [30]=3 [137]=3 [71]=3 [100]=3)"
literal_transitions[10]="([115]=16 [112]=17)"
literal_transitions[12]="([102]=3)"
literal_transitions[14]="([22]=2 [117]=2 [31]=2 [136]=2 [119]=2 [44]=2 [72]=2)"
literal_transitions[15]="([39]=3)"
literal_transitions[16]="([9]=3 [67]=3 [15]=3 [134]=3)"
literal_transitions[18]="([76]=20)"
literal_transitions[19]="([19]=3 [8]=3)"
literal_transitions[20]="([35]=6 [45]=6)"
literal_transitions[21]="([135]=3 [95]=3)"
local -A match_anything_transitions
match_anything_transitions=([2]=3 [1]=8 [7]=3 [21]=3 [11]=3 [3]=18 [8]=8 [13]=3 [15]=18 [17]=3 [5]=21 [12]=18)
declare -A subword_transitions
local state=1
local word_index=2
while [[ $word_index -lt $CURRENT ]]; do
if [[ -v "literal_transitions[$state]" ]]; then
local -A state_transitions
eval "state_transitions=${literal_transitions[$state]}"
local word=${words[$word_index]}
local word_matched=0
for ((literal_id = 1; literal_id <= $#literals; literal_id++)); do
if [[ ${literals[$literal_id]} = "$word" ]]; then
if [[ -v "state_transitions[$literal_id]" ]]; then
state=${state_transitions[$literal_id]}
word_index=$((word_index + 1))
word_matched=1
break
fi
fi
done
if [[ $word_matched -ne 0 ]]; then
continue
fi
fi
if [[ -v "match_anything_transitions[$state]" ]]; then
state=${match_anything_transitions[$state]}
word_index=$((word_index + 1))
continue
fi
return 1
done
completions_no_description_trailing_space=()
completions_no_description_no_trailing_space=()
completions_trailing_space=()
suffixes_trailing_space=()
descriptions_trailing_space=()
completions_no_trailing_space=()
suffixes_no_trailing_space=()
descriptions_no_trailing_space=()
if [[ -v "literal_transitions[$state]" ]]; then
local -A state_transitions
eval "state_transitions=${literal_transitions[$state]}"
for literal_id in ${(k)state_transitions}; do
if [[ -v "descriptions[$literal_id]" ]]; then
completions_trailing_space+=("${literals[$literal_id]}")
suffixes_trailing_space+=("${literals[$literal_id]}")
descriptions_trailing_space+=("${descriptions[$literal_id]}")
else
completions_no_description_trailing_space+=("${literals[$literal_id]}")
fi
done
fi
local -A commands=([17]=2 [5]=3 [13]=1 [11]=0)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
local output=$(_hyprctl_cmd_${command_id} "${words[$CURRENT]}")
local -a command_completions=("${(@f)output}")
for line in ${command_completions[@]}; do
local parts=(${(@s: :)line})
if [[ -v "parts[2]" ]]; then
completions_trailing_space+=("${parts[1]}")
suffixes_trailing_space+=("${parts[1]}")
descriptions_trailing_space+=("${parts[2]}")
else
completions_no_description_trailing_space+=("${parts[1]}")
fi
done
fi
local maxlen=0
for suffix in ${suffixes_trailing_space[@]}; do
if [[ ${#suffix} -gt $maxlen ]]; then
maxlen=${#suffix}
fi
done
for suffix in ${suffixes_no_trailing_space[@]}; do
if [[ ${#suffix} -gt $maxlen ]]; then
maxlen=${#suffix}
fi
done
for ((i = 1; i <= $#suffixes_trailing_space; i++)); do
if [[ -z ${descriptions_trailing_space[$i]} ]]; then
descriptions_trailing_space[$i]="${(r($maxlen)( ))${suffixes_trailing_space[$i]}}"
else
descriptions_trailing_space[$i]="${(r($maxlen)( ))${suffixes_trailing_space[$i]}} -- ${descriptions_trailing_space[$i]}"
fi
done
for ((i = 1; i <= $#suffixes_no_trailing_space; i++)); do
if [[ -z ${descriptions_no_trailing_space[$i]} ]]; then
descriptions_no_trailing_space[$i]="${(r($maxlen)( ))${suffixes_no_trailing_space[$i]}}"
else
descriptions_no_trailing_space[$i]="${(r($maxlen)( ))${suffixes_no_trailing_space[$i]}} -- ${descriptions_no_trailing_space[$i]}"
fi
done
compadd -Q -a completions_no_description_trailing_space
compadd -Q -S ' ' -a completions_no_description_no_trailing_space
compadd -l -Q -a -d descriptions_trailing_space completions_trailing_space
compadd -l -Q -S '' -a -d descriptions_no_trailing_space completions_no_trailing_space
return 0
}
compdef _hyprctl hyprctl

View File

@@ -22,47 +22,9 @@
#include <deque> #include <deque>
#include <filesystem> #include <filesystem>
#include <stdarg.h> #include <stdarg.h>
#include <regex>
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args] #include "Strings.hpp"
commands:
activewindow
activeworkspace
binds
clients
cursorpos
decorations
devices
dismissnotify
dispatch
getoption
globalshortcuts
hyprpaper
instances
keyword
kill
layers
layouts
monitors
notify
plugin
reload
setcursor
seterror
setprop
splash
switchxkblayout
systeminfo
version
workspacerules
workspaces
flags:
-j -> output in JSON
-r -> refresh state after issuing command (e.g. for updating variables)
--batch -> execute a batch of commands, separated by ';'
--instance (-i) -> use a specific instance. Can be either signature or index in hyprctl instances (0, 1, etc)
)#";
#define PAD #define PAD
@@ -231,9 +193,14 @@ void requestHyprpaper(std::string arg) {
std::cout << std::string(buffer); std::cout << std::string(buffer);
} }
void batchRequest(std::string arg) { void batchRequest(std::string arg, bool json) {
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1); std::string commands = arg.substr(arg.find_first_of(" ") + 1);
if (json) {
commands = "j/" + std::regex_replace(commands, std::regex(";\\s*"), ";j/");
}
std::string rq = "[[BATCH]]" + commands;
request(rq); request(rq);
} }
@@ -286,7 +253,7 @@ int main(int argc, char** argv) {
bool parseArgs = true; bool parseArgs = true;
if (argc < 2) { if (argc < 2) {
printf("%s\n", USAGE.c_str()); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -317,13 +284,33 @@ int main(int argc, char** argv) {
++i; ++i;
if (i >= ARGS.size()) { if (i >= ARGS.size()) {
printf("%s\n", USAGE.c_str()); std::cout << USAGE << std::endl;
return 1; return 1;
} }
overrideInstance = ARGS[i]; overrideInstance = ARGS[i];
} else if (ARGS[i] == "--help") {
const std::string& cmd = ARGS[0];
if (cmd == "hyprpaper") {
std::cout << HYPRPAPER_HELP << std::endl;
} else if (cmd == "notify") {
std::cout << NOTIFY_HELP << std::endl;
} else if (cmd == "output") {
std::cout << OUTPUT_HELP << std::endl;
} else if (cmd == "plugin") {
std::cout << PLUGIN_HELP << std::endl;
} else if (cmd == "setprop") {
std::cout << SETPROP_HELP << std::endl;
} else if (cmd == "switchxkblayout") {
std::cout << SWITCHXKBLAYOUT_HELP << std::endl;
} else { } else {
printf("%s\n", USAGE.c_str()); std::cout << USAGE << std::endl;
}
return 1;
} else {
std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -334,7 +321,7 @@ int main(int argc, char** argv) {
} }
if (fullRequest.empty()) { if (fullRequest.empty()) {
printf("%s\n", USAGE.c_str()); std::cout << USAGE << std::endl;
return 1; return 1;
} }
@@ -380,7 +367,7 @@ int main(int argc, char** argv) {
int exitStatus = 0; int exitStatus = 0;
if (fullRequest.contains("/--batch")) if (fullRequest.contains("/--batch"))
batchRequest(fullRequest); batchRequest(fullRequest, json);
else if (fullRequest.contains("/hyprpaper")) else if (fullRequest.contains("/hyprpaper"))
requestHyprpaper(fullRequest); requestHyprpaper(fullRequest);
else if (fullRequest.contains("/switchxkblayout")) else if (fullRequest.contains("/switchxkblayout"))
@@ -406,11 +393,11 @@ int main(int argc, char** argv) {
else if (fullRequest.contains("/decorations")) else if (fullRequest.contains("/decorations"))
request(fullRequest, 1); request(fullRequest, 1);
else if (fullRequest.contains("/--help")) else if (fullRequest.contains("/--help"))
printf("%s", USAGE.c_str()); std::cout << USAGE << std::endl;
else { else {
request(fullRequest); request(fullRequest);
} }
printf("\n"); std::cout << std::endl;
return exitStatus; return exitStatus;
} }

View File

@@ -1,3 +1,7 @@
executable('hyprctl', 'main.cpp', executable('hyprctl', 'main.cpp',
install: true install: true
) )
install_data('hyprctl.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion'), 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

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

106
hyprpm/hyprpm.bash Normal file
View File

@@ -0,0 +1,106 @@
_hyprpm_cmd_0 () {
hyprpm list | grep Plugin | awk '{print $4}'
}
_hyprpm () {
if [[ $(type -t _get_comp_words_by_ref) != function ]]; then
echo _get_comp_words_by_ref: function not defined. Make sure the bash-completions system package is installed
return 1
fi
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 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)
declare -A subword_transitions
local state=0
local word_index=1
while [[ $word_index -lt $cword ]]; do
local word=${words[$word_index]}
if [[ -v "literal_transitions[$state]" ]]; then
declare -A state_transitions
eval "state_transitions=${literal_transitions[$state]}"
local word_matched=0
for literal_id in $(seq 0 $((${#literals[@]} - 1))); do
if [[ ${literals[$literal_id]} = "$word" ]]; then
if [[ -v "state_transitions[$literal_id]" ]]; then
state=${state_transitions[$literal_id]}
word_index=$((word_index + 1))
word_matched=1
break
fi
fi
done
if [[ $word_matched -ne 0 ]]; then
continue
fi
fi
if [[ -v "match_anything_transitions[$state]" ]]; then
state=${match_anything_transitions[$state]}
word_index=$((word_index + 1))
continue
fi
return 1
done
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
eval "state_transitions=$state_transitions_initializer"
for literal_id in "${!state_transitions[@]}"; do
local literal="${literals[$literal_id]}"
if [[ $literal = "${prefix}"* ]]; then
local completion=${literal#"$superfluous_prefix"}
COMPREPLY+=("$completion ")
fi
done
fi
declare -A commands
commands=([3]=0)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
local completions=()
mapfile -t completions < <(_hyprpm_cmd_${command_id} "$prefix" | cut -f1)
for item in "${completions[@]}"; do
if [[ $item = "${prefix}"* ]]; then
COMPREPLY+=("$item")
fi
done
fi
return 0
}
complete -o nospace -F _hyprpm hyprpm

109
hyprpm/hyprpm.fish Normal file
View File

@@ -0,0 +1,109 @@
function _hyprpm_1
set 1 $argv[1]
hyprpm list | grep Plugin | awk '{print $4}'
end
function _hyprpm
set COMP_LINE (commandline --cut-at-cursor)
set COMP_WORDS
echo $COMP_LINE | read --tokenize --array COMP_WORDS
if string match --quiet --regex '.*\s$' $COMP_LINE
set COMP_CWORD (math (count $COMP_WORDS) + 1)
else
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 --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[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[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 --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 --local match_anything_transitions_from 4 3 1 2
set --local match_anything_transitions_to 3 5 2 2
set --local state 1
set --local word_index 2
while test $word_index -lt $COMP_CWORD
set --local -- word $COMP_WORDS[$word_index]
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
set --local --erase inputs
set --local --erase tos
eval $literal_transitions[$state]
if contains -- $word $literals
set --local 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 state $tos[$index]
set word_index (math $word_index + 1)
set literal_matched 1
break
end
end
if test $literal_matched -ne 0
continue
end
end
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 state $match_anything_transitions_to[$index]
set word_index (math $word_index + 1)
continue
end
return 1
end
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
set --local --erase inputs
set --local --erase tos
eval $literal_transitions[$state]
for literal_id in $inputs
if test -n $descriptions[$literal_id]
printf '%s\t%s\n' $literals[$literal_id] $descriptions[$literal_id]
else
printf '%s\n' $literals[$literal_id]
end
end
end
set command_states 4
set command_ids 1
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
$function_name "$COMP_WORDS[$COMP_CWORD]"
end
return 0
end
complete --command hyprpm --no-files --arguments "(_hyprpm)"

19
hyprpm/hyprpm.usage Normal file
View File

@@ -0,0 +1,19 @@
hyprpm [<FLAGS>]... <ARGUMENT>
<FLAGS> ::= (--notify | -n) "Send a hyprland notification for important events (e.g. load fail)"
| (--help | -h) "Show help menu"
| (--verbose | -v) "Enable too much loggin"
| (--force | -f) "Force an operation ignoring checks (e.g. update -f)"
;
<ARGUMENT> ::= (add) "Install a new plugin repository from git"
| (remove) "Remove a plugin repository"
| (update) "Check and update all plugins if needed"
| (list) "List all installed plugins"
| (enable <PLUGINS>) "Load a plugin"
| (disable <PLUGINS>) "Unload a plugin"
| (reload) "Reload all plugins"
;
<PLUGINS> ::= {{{ hyprpm list | grep Plugin | awk '{print $4}' }}};

151
hyprpm/hyprpm.zsh Normal file
View File

@@ -0,0 +1,151 @@
#compdef hyprpm
_hyprpm_cmd_0 () {
hyprpm list | grep Plugin | awk '{print $4}'
}
_hyprpm () {
local -a literals=("-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "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[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[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)"
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)"
local -A match_anything_transitions
match_anything_transitions=([4]=3 [3]=5 [1]=2 [2]=2)
declare -A subword_transitions
local state=1
local word_index=2
while [[ $word_index -lt $CURRENT ]]; do
if [[ -v "literal_transitions[$state]" ]]; then
local -A state_transitions
eval "state_transitions=${literal_transitions[$state]}"
local word=${words[$word_index]}
local word_matched=0
for ((literal_id = 1; literal_id <= $#literals; literal_id++)); do
if [[ ${literals[$literal_id]} = "$word" ]]; then
if [[ -v "state_transitions[$literal_id]" ]]; then
state=${state_transitions[$literal_id]}
word_index=$((word_index + 1))
word_matched=1
break
fi
fi
done
if [[ $word_matched -ne 0 ]]; then
continue
fi
fi
if [[ -v "match_anything_transitions[$state]" ]]; then
state=${match_anything_transitions[$state]}
word_index=$((word_index + 1))
continue
fi
return 1
done
completions_no_description_trailing_space=()
completions_no_description_no_trailing_space=()
completions_trailing_space=()
suffixes_trailing_space=()
descriptions_trailing_space=()
completions_no_trailing_space=()
suffixes_no_trailing_space=()
descriptions_no_trailing_space=()
if [[ -v "literal_transitions[$state]" ]]; then
local -A state_transitions
eval "state_transitions=${literal_transitions[$state]}"
for literal_id in ${(k)state_transitions}; do
if [[ -v "descriptions[$literal_id]" ]]; then
completions_trailing_space+=("${literals[$literal_id]}")
suffixes_trailing_space+=("${literals[$literal_id]}")
descriptions_trailing_space+=("${descriptions[$literal_id]}")
else
completions_no_description_trailing_space+=("${literals[$literal_id]}")
fi
done
fi
local -A commands=([4]=0)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
local output=$(_hyprpm_cmd_${command_id} "${words[$CURRENT]}")
local -a command_completions=("${(@f)output}")
for line in ${command_completions[@]}; do
local parts=(${(@s: :)line})
if [[ -v "parts[2]" ]]; then
completions_trailing_space+=("${parts[1]}")
suffixes_trailing_space+=("${parts[1]}")
descriptions_trailing_space+=("${parts[2]}")
else
completions_no_description_trailing_space+=("${parts[1]}")
fi
done
fi
local maxlen=0
for suffix in ${suffixes_trailing_space[@]}; do
if [[ ${#suffix} -gt $maxlen ]]; then
maxlen=${#suffix}
fi
done
for suffix in ${suffixes_no_trailing_space[@]}; do
if [[ ${#suffix} -gt $maxlen ]]; then
maxlen=${#suffix}
fi
done
for ((i = 1; i <= $#suffixes_trailing_space; i++)); do
if [[ -z ${descriptions_trailing_space[$i]} ]]; then
descriptions_trailing_space[$i]="${(r($maxlen)( ))${suffixes_trailing_space[$i]}}"
else
descriptions_trailing_space[$i]="${(r($maxlen)( ))${suffixes_trailing_space[$i]}} -- ${descriptions_trailing_space[$i]}"
fi
done
for ((i = 1; i <= $#suffixes_no_trailing_space; i++)); do
if [[ -z ${descriptions_no_trailing_space[$i]} ]]; then
descriptions_no_trailing_space[$i]="${(r($maxlen)( ))${suffixes_no_trailing_space[$i]}}"
else
descriptions_no_trailing_space[$i]="${(r($maxlen)( ))${suffixes_no_trailing_space[$i]}} -- ${descriptions_no_trailing_space[$i]}"
fi
done
compadd -Q -a completions_no_description_trailing_space
compadd -Q -S ' ' -a completions_no_description_no_trailing_space
compadd -l -Q -a -d descriptions_trailing_space completions_trailing_space
compadd -l -Q -S '' -a -d descriptions_no_trailing_space completions_no_trailing_space
return 0
}
if [[ $ZSH_EVAL_CONTEXT =~ :file$ ]]; then
compdef _hyprpm hyprpm
else
_hyprpm
fi

View File

@@ -75,6 +75,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) {
for (auto& plugin : m_vPlugins) { for (auto& plugin : m_vPlugins) {
plugin.description = manifest[plugin.name]["description"].value_or("?"); plugin.description = manifest[plugin.name]["description"].value_or("?");
plugin.output = manifest[plugin.name]["output"].value_or("?"); plugin.output = manifest[plugin.name]["output"].value_or("?");
plugin.since = manifest[plugin.name]["since_hyprland"].value_or(0);
auto authors = manifest[plugin.name]["authors"].as_array(); auto authors = manifest[plugin.name]["authors"].as_array();
if (authors) { if (authors) {
for (auto&& a : *authors) { for (auto&& a : *authors) {

View File

@@ -19,6 +19,7 @@ class CManifest {
std::vector<std::string> authors; std::vector<std::string> authors;
std::vector<std::string> buildSteps; std::vector<std::string> buildSteps;
std::string output; std::string output;
int since = 0;
bool failed = false; bool failed = false;
}; };

View File

@@ -70,16 +70,36 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
std::string hlbranch = HLVERCALL.substr(HLVERCALL.find("from branch") + 12); std::string hlbranch = HLVERCALL.substr(HLVERCALL.find("from branch") + 12);
hlbranch = hlbranch.substr(0, hlbranch.find(" at commit ")); hlbranch = hlbranch.substr(0, hlbranch.find(" at commit "));
if (m_bVerbose) std::string hldate = HLVERCALL.substr(HLVERCALL.find("Date: ") + 6);
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << "\n"; hldate = hldate.substr(0, hldate.find("\n"));
ver = SHyprlandVersion{hlbranch, hlcommit}; std::string hlcommits;
if (HLVERCALL.contains("commits:")) {
hlcommits = HLVERCALL.substr(HLVERCALL.find("commits:") + 9);
hlcommits = hlcommits.substr(0, hlcommits.find(" "));
}
int commits = 0;
try {
commits = std::stoi(hlcommits);
} catch (...) { ; }
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << " on " << hldate << ", commits " << commits << "\n";
ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits};
return ver; return ver;
} }
bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& rev) { bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& rev) {
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
return false;
}
if (DataState::pluginRepoExists(url)) { if (DataState::pluginRepoExists(url)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n"; std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
return false; return false;
@@ -214,6 +234,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
for (auto& p : pManifest->m_vPlugins) { for (auto& p : pManifest->m_vPlugins) {
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
p.failed = true;
continue;
}
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) { for (auto& bs : p.buildSteps) {
@@ -221,14 +247,16 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string&
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Plugin " + p.name + " failed to build.\n");
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n"; std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
p.failed = true; if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Plugin " + p.name + " failed to build.\n" +
" This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update "
"first.\n Try re-running with -v to see "
"more verbose output.\n");
p.failed = true;
continue; continue;
} }
@@ -297,7 +325,7 @@ eHeadersErrors CPluginManager::headersValid() {
return HEADERS_MISSING; return HEADERS_MISSING;
// find headers commit // find headers commit
std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkg-config --cflags --keep-system-cflags hyprland", DataState::getHeadersPath()); std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
auto headers = execAndGet(cmd.c_str()); auto headers = execAndGet(cmd.c_str());
if (!headers.contains("-I/")) if (!headers.contains("-I/"))
@@ -315,7 +343,7 @@ eHeadersErrors CPluginManager::headersValid() {
else else
headers = ""; headers = "";
if (PATH.ends_with("protocols") || PATH.ends_with("wlroots")) if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland"))
continue; continue;
verHeader = removeBeginEndSpacesTabs(PATH.substr(2)) + "/hyprland/src/version.h"; verHeader = removeBeginEndSpacesTabs(PATH.substr(2)) + "/hyprland/src/version.h";
@@ -333,7 +361,12 @@ eHeadersErrors CPluginManager::headersValid() {
std::string verHeaderContent((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>())); std::string verHeaderContent((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
ifs.close(); ifs.close();
std::string hash = verHeaderContent.substr(verHeaderContent.find("#define GIT_COMMIT_HASH") + 23); const auto HASHPOS = verHeaderContent.find("#define GIT_COMMIT_HASH");
if (HASHPOS == std::string::npos || HASHPOS + 23 >= verHeaderContent.length())
return HEADERS_CORRUPTED;
std::string hash = verHeaderContent.substr(HASHPOS + 23);
hash = hash.substr(0, hash.find_first_of('\n')); hash = hash.substr(0, hash.find_first_of('\n'));
hash = hash.substr(hash.find_first_of('"') + 1); hash = hash.substr(hash.find_first_of('"') + 1);
hash = hash.substr(0, hash.find_first_of('"')); hash = hash.substr(0, hash.find_first_of('"'));
@@ -350,6 +383,11 @@ bool CPluginManager::updateHeaders(bool force) {
const auto HLVER = getHyprlandVersion(); const auto HLVER = getHyprlandVersion();
if (!hasDeps()) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n";
return false;
}
if (!std::filesystem::exists("/tmp/hyprpm")) { if (!std::filesystem::exists("/tmp/hyprpm")) {
std::filesystem::create_directory("/tmp/hyprpm"); std::filesystem::create_directory("/tmp/hyprpm");
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace); std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
@@ -373,7 +411,19 @@ bool CPluginManager::updateHeaders(bool force) {
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment.");
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland"); // let us give a bit of leg-room for shallowing
// due to timezones, etc.
const std::string SHALLOW_DATE = removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'");
if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE);
std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland --shallow-since='" + SHALLOW_DATE + "'");
if (!std::filesystem::exists("/tmp/hyprpm/hyprland")) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Clone failed. Retrying without shallow.");
ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland");
}
if (!std::filesystem::exists("/tmp/hyprpm/hyprland")) { if (!std::filesystem::exists("/tmp/hyprpm/hyprland")) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n"; std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n";
@@ -385,11 +435,15 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Checking out sources"; progress.m_szCurrentMessage = "Checking out sources";
progress.print(); progress.print();
ret = ret = execAndGet("cd /tmp/hyprpm/hyprland && git checkout " + HLVER.branch + " 2>&1");
execAndGet("cd /tmp/hyprpm/hyprland && git checkout " + HLVER.branch + " 2>&1 && git submodule update --init 2>&1 && git reset --hard --recurse-submodules " + HLVER.hash);
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned: " + ret); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret);
ret = execAndGet("cd /tmp/hyprpm/hyprland && 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);
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " checked out to running ver"); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " checked out to running ver");
progress.m_iSteps = 3; progress.m_iSteps = 3;
@@ -408,7 +462,7 @@ bool CPluginManager::updateHeaders(bool force) {
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
// le hack. Wlroots has to generate its build/include // le hack. Wlroots has to generate its build/include
ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots && meson setup -Drenderers=gles2 -Dexamples=false build"); ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots-hyprland && meson setup -Drenderers=gles2 -Dexamples=false build");
if (m_bVerbose) if (m_bVerbose)
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret); progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret);
@@ -417,10 +471,6 @@ bool CPluginManager::updateHeaders(bool force) {
progress.m_szCurrentMessage = "Installing sources"; progress.m_szCurrentMessage = "Installing sources";
progress.print(); progress.print();
// progress.printMessageAbove(
// std::string{Colors::YELLOW} + "!" + Colors::RESET +
// " in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" /tmp/hyprpm/hyprland/Makefile && cd /tmp/hyprpm/hyprland && make installheaders", std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" /tmp/hyprpm/hyprland/Makefile && cd /tmp/hyprpm/hyprland && make installheaders",
DataState::getHeadersPath()); DataState::getHeadersPath());
if (m_bVerbose) if (m_bVerbose)
@@ -505,7 +555,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
if (!repo.rev.empty()) { if (!repo.rev.empty()) {
progress.printMessageAbove(std::string{Colors::RESET} + " → Plugin has revision set, resetting: " + repo.rev); progress.printMessageAbove(std::string{Colors::RESET} + " → Plugin has revision set, resetting: " + repo.rev);
std::string ret = execAndGet("git -C /tmp/hyprpm reset --hard --recurse-submodules " + repo.rev); std::string ret = execAndGet("git -C /tmp/hyprpm/update reset --hard --recurse-submodules " + repo.rev);
if (ret.compare(0, 6, "fatal:") == 0) { if (ret.compare(0, 6, "fatal:") == 0) {
std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret; std::cout << "\n" << std::string{Colors::RED} + "" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret;
return false; return false;
@@ -571,10 +621,15 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
} }
} }
bool failed = false;
for (auto& p : pManifest->m_vPlugins) { for (auto& p : pManifest->m_vPlugins) {
std::string out; std::string out;
if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) {
progress.printMessageAbove(std::string{Colors::RED} + "" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n");
p.failed = true;
continue;
}
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
for (auto& bs : p.buildSteps) { for (auto& bs : p.buildSteps) {
@@ -582,20 +637,22 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
} }
if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Plugin " << p.name << " failed to build.\n";
failed = true;
if (m_bVerbose) if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n"; std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
break;
if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) {
std::cerr << "\n"
<< Colors::RED << "" << Colors::RESET << " Plugin " << p.name << " failed to build.\n"
<< " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update first.\n Try "
"re-running with -v to see more verbose "
"output.\n";
p.failed = true;
continue;
} }
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output); progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " built " + p.name + " into " + p.output);
} }
if (failed)
continue;
// add repo toml to DataState // add repo toml to DataState
SPluginRepository newrepo = repo; SPluginRepository newrepo = repo;
newrepo.plugins.clear(); newrepo.plugins.clear();
@@ -786,3 +843,13 @@ std::string CPluginManager::headerError(const eHeadersErrors err) {
return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n"; return std::string{Colors::RED} + "" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n";
} }
bool CPluginManager::hasDeps() {
std::vector<std::string> deps = {"meson", "cpio", "cmake"};
for (auto& d : deps) {
if (!execAndGet("which " + d + " 2>&1").contains("/"))
return false;
}
return true;
}

View File

@@ -32,6 +32,8 @@ enum ePluginLoadStateReturn {
struct SHyprlandVersion { struct SHyprlandVersion {
std::string branch; std::string branch;
std::string hash; std::string hash;
std::string date;
int commits = 0;
}; };
class CPluginManager { class CPluginManager {
@@ -54,6 +56,8 @@ class CPluginManager {
void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message); void notify(const eNotifyIcons icon, uint32_t color, int durationMs, const std::string& message);
bool hasDeps();
bool m_bVerbose = false; bool m_bVerbose = false;
private: private:

View File

@@ -56,7 +56,7 @@ int main(int argc, char** argv, char** envp) {
force = true; force = true;
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n"; std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
} else { } else {
std::cerr << "Unrecognized option " << ARGS[i]; std::cerr << "Unrecognized option " << ARGS[i] << "\n";
return 1; return 1;
} }
} else { } else {

View File

@@ -8,3 +8,7 @@ executable('hyprpm', src,
], ],
install : true install : true
) )
install_data('../hyprpm.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion'), 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

@@ -33,7 +33,7 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif endif
wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2']) wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2'])
have_xwlr = wlroots.get_variable('features').get('xwayland') have_xwlr = wlroots.get_variable('features').get('xwayland')
xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_dep = dependency('xcb', required: get_option('xwayland'))
@@ -51,6 +51,7 @@ if not have_xwayland
endif endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false) backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs
systemd_dep = dependency('libsystemd', required: get_option('systemd')) systemd_dep = dependency('libsystemd', required: get_option('systemd'))
if get_option('systemd').enabled() if get_option('systemd').enabled()

View File

@@ -2,6 +2,7 @@
lib, lib,
stdenv, stdenv,
pkg-config, pkg-config,
pkgconf,
makeWrapper, makeWrapper,
meson, meson,
ninja, ninja,
@@ -14,6 +15,7 @@
jq, jq,
libGL, libGL,
libdrm, libdrm,
libexecinfo,
libinput, libinput,
libxcb, libxcb,
libxkbcommon, libxkbcommon,
@@ -26,7 +28,7 @@
wayland, wayland,
wayland-protocols, wayland-protocols,
wayland-scanner, wayland-scanner,
wlroots, wlroots-hyprland,
xcbutilwm, xcbutilwm,
xwayland, xwayland,
debug ? false, debug ? false,
@@ -44,7 +46,9 @@
}: }:
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` 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"; assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; let
wlr = wlroots-hyprland.override {inherit enableXWayland;};
in
stdenv.mkDerivation { stdenv.mkDerivation {
pname = "hyprland${lib.optionalString debug "-debug"}"; pname = "hyprland${lib.optionalString debug "-debug"}";
inherit version; inherit version;
@@ -57,57 +61,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
src = lib.cleanSource ../.; src = lib.cleanSource ../.;
}; };
nativeBuildInputs = [
jq
meson
ninja
pkg-config
makeWrapper
wayland-scanner
];
outputs = [
"out"
"man"
"dev"
];
buildInputs =
[
cairo
git
hyprcursor.dev
hyprland-protocols
hyprlang
libdrm
libGL
libinput
libxkbcommon
mesa
pango
pciutils
tomlplusplus
udis86
wayland
wayland-protocols
wlroots
]
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
++ lib.optionals withSystemd [systemd];
mesonBuildType =
if debug
then "debug"
else "release";
mesonAutoFeatures = "disabled";
mesonFlags = builtins.concatLists [
(lib.optional enableXWayland "-Dxwayland=enabled")
(lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
(lib.optional withSystemd "-Dsystemd=enabled")
];
patches = [ patches = [
# make meson use the provided wlroots instead of the git submodule # make meson use the provided wlroots instead of the git submodule
./patches/meson-build.patch ./patches/meson-build.patch
@@ -132,8 +85,61 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
}' }'
''; '';
nativeBuildInputs = [
jq
makeWrapper
meson
ninja
pkg-config
wayland-scanner
];
outputs = [
"out"
"man"
"dev"
];
buildInputs =
wlr.buildInputs
++ [
cairo
git
hyprcursor.dev
hyprland-protocols
hyprlang
libdrm
libGL
libinput
libxkbcommon
mesa
pango
pciutils
tomlplusplus
udis86
wayland
wayland-protocols
wlr
]
++ lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]
++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland]
++ lib.optionals withSystemd [systemd];
mesonBuildType =
if debug
then "debug"
else "release";
mesonAutoFeatures = "disabled";
mesonFlags = [
(lib.mesonEnable "xwayland" enableXWayland)
(lib.mesonEnable "legacy_renderer" legacyRenderer)
(lib.mesonEnable "systemd" withSystemd)
];
postInstall = '' postInstall = ''
ln -s ${wlroots}/include/wlr $dev/include/hyprland/wlroots ln -s ${wlr}/include/wlr $dev/include/hyprland/wlroots
${lib.optionalString wrapRuntimeDeps '' ${lib.optionalString wrapRuntimeDeps ''
wrapProgram $out/bin/Hyprland \ wrapProgram $out/bin/Hyprland \
@@ -141,6 +147,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
stdenv.cc stdenv.cc
binutils binutils
pciutils pciutils
pkgconf
]} ]}
''} ''}
''; '';
@@ -148,10 +155,10 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
passthru.providedSessions = ["hyprland"]; passthru.providedSessions = ["hyprland"];
meta = with lib; { meta = with lib; {
homepage = "https://github.com/vaxerski/Hyprland"; homepage = "https://github.com/hyprwm/Hyprland";
description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
license = licenses.bsd3; license = licenses.bsd3;
platforms = platforms.linux; platforms = wlr.meta.platforms;
mainProgram = "Hyprland"; mainProgram = "Hyprland";
}; };
} }

View File

@@ -34,8 +34,8 @@ in {
stdenv = final.gcc13Stdenv; stdenv = final.gcc13Stdenv;
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}"; version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
commit = self.rev or ""; commit = self.rev or "";
wlroots = final.wlroots-hyprland; # explicit override until decided on breaking change of the name
udis86 = final.udis86-hyprland; # explicit override until decided on breaking change of the name udis86 = final.udis86-hyprland; # explicit override until decided on breaking change of the name
inherit (final) wlroots-hyprland; # explicit override until decided on breaking change of the name
inherit date; inherit date;
}; };
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;}; hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};

View File

@@ -6,7 +6,7 @@ index 1d2c7f9f..c5ef4e67 100644
add_project_arguments('-DHAS_EXECINFO', language: 'cpp') add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif endif
-wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2']) -wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2'])
-have_xwlr = wlroots.get_variable('features').get('xwayland') -have_xwlr = wlroots.get_variable('features').get('xwayland')
-xcb_dep = dependency('xcb', required: get_option('xwayland')) -xcb_dep = dependency('xcb', required: get_option('xwayland'))
- -
@@ -46,13 +46,14 @@ index 45701f5f..3505cefe 100644
dependency('cairo'), dependency('cairo'),
dependency('hyprcursor'), dependency('hyprcursor'),
dependency('hyprlang', version: '>= 0.3.2'), dependency('hyprlang', version: '>= 0.3.2'),
@@ -16,12 +16,12 @@ executable('Hyprland', src, @@ -17,11 +17,11 @@ executable('Hyprland', src,
dependency('egl'), dependency('egl'),
dependency('xkbcommon'), dependency('xkbcommon'),
dependency('libinput'), dependency('libinput'),
- xcb_dep, - xcb_dep,
+ dependency('xcb', required: get_option('xwayland')), + dependency('xcb', required: get_option('xwayland')),
backtrace_dep, backtrace_dep,
epoll_dep,
systemd_dep, systemd_dep,
- udis86, - udis86,
+ dependency('udis86'), + dependency('udis86'),

View File

@@ -1,3 +1,3 @@
{ {
"version": "0.37.0" "version": "0.39.1"
} }

View File

@@ -2,11 +2,12 @@
cp -fr ./src/version.h.in ./src/version.h cp -fr ./src/version.h.in ./src/version.h
HASH=$(git rev-parse HEAD) HASH=$(git rev-parse HEAD)
BRANCH=$(git rev-parse --abbrev-ref HEAD) BRANCH=$(git branch --show-current)
MESSAGE=$(git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g') MESSAGE=$(git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g')
DATE=$(git show ${GIT_COMMIT_HASH} --no-patch --format=%cd --date=local) DATE=$(git show ${GIT_COMMIT_HASH} --no-patch --format=%cd --date=local)
DIRTY=$(git diff-index --quiet HEAD -- || echo dirty) DIRTY=$(git diff-index --quiet HEAD -- || echo dirty)
TAG=$(git describe --tags) TAG=$(git describe --tags)
COMMITS=$(git rev-list --count HEAD)
sed -i -e "s#@HASH@#${HASH}#" ./src/version.h sed -i -e "s#@HASH@#${HASH}#" ./src/version.h
sed -i -e "s#@BRANCH@#${BRANCH}#" ./src/version.h sed -i -e "s#@BRANCH@#${BRANCH}#" ./src/version.h
@@ -14,3 +15,4 @@ sed -i -e "s#@MESSAGE@#${MESSAGE}#" ./src/version.h
sed -i -e "s#@DATE@#${DATE}#" ./src/version.h sed -i -e "s#@DATE@#${DATE}#" ./src/version.h
sed -i -e "s#@DIRTY@#${DIRTY}#" ./src/version.h sed -i -e "s#@DIRTY@#${DIRTY}#" ./src/version.h
sed -i -e "s#@TAG@#${TAG}#" ./src/version.h sed -i -e "s#@TAG@#${TAG}#" ./src/version.h
sed -i -e "s#@COMMITS@#${COMMITS}#" ./src/version.h

View File

@@ -1,17 +1,16 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt
index 857e21de..122d6a78 100755 index 1190876d..0e7573f9 100755
--- a/CMakeLists.txt --- a/CMakeLists.txt
+++ b/CMakeLists.txt +++ b/CMakeLists.txt
@@ -101,7 +101,7 @@ message(STATUS "Checking deps...") @@ -110,6 +110,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET
find_package(Threads REQUIRED) cairo pango pangocairo pixman-1
find_package(PkgConfig REQUIRED) libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm
find_package(OpenGL REQUIRED) hyprlang>=0.3.2 hyprcursor
-pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2) # we do not check for wlroots, as we provide it ourselves + libffi
+pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2 libffi) # we do not check for wlroots, as we provide it ourselves )
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
@@ -130,6 +131,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
@@ -121,6 +121,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Enabling ASan") message(STATUS "Enabling ASan")
target_link_libraries(Hyprland asan) target_link_libraries(Hyprland asan)

View File

@@ -2,6 +2,7 @@
#include "helpers/Splashes.hpp" #include "helpers/Splashes.hpp"
#include "config/ConfigValue.hpp" #include "config/ConfigValue.hpp"
#include "managers/CursorManager.hpp" #include "managers/CursorManager.hpp"
#include "managers/eventLoop/EventLoopManager.hpp"
#include <random> #include <random>
#include <unordered_set> #include <unordered_set>
#include "debug/HyprCtl.hpp" #include "debug/HyprCtl.hpp"
@@ -10,6 +11,7 @@
#include <systemd/sd-daemon.h> // for sd_notify #include <systemd/sd-daemon.h> // for sd_notify
#endif #endif
#include <ranges> #include <ranges>
#include "helpers/VarList.hpp"
int handleCritSignal(int signo, void* data) { int handleCritSignal(int signo, void* data) {
Debug::log(LOG, "Hyprland received signal {}", signo); Debug::log(LOG, "Hyprland received signal {}", signo);
@@ -417,12 +419,10 @@ void CCompositor::cleanup() {
g_pXWaylandManager->m_sWLRXWayland = nullptr; g_pXWaylandManager->m_sWLRXWayland = nullptr;
} }
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
removeAllSignals(); removeAllSignals();
g_pInputManager.reset(); g_pInputManager.reset();
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
g_pDecorationPositioner.reset(); g_pDecorationPositioner.reset();
g_pCursorManager.reset(); g_pCursorManager.reset();
g_pPluginSystem.reset(); g_pPluginSystem.reset();
@@ -452,6 +452,9 @@ void CCompositor::cleanup() {
void CCompositor::initManagers(eManagersInitStage stage) { void CCompositor::initManagers(eManagersInitStage stage) {
switch (stage) { switch (stage) {
case STAGE_PRIORITY: { case STAGE_PRIORITY: {
Debug::log(LOG, "Creating the EventLoopManager!");
g_pEventLoopManager = std::make_unique<CEventLoopManager>();
Debug::log(LOG, "Creating the HookSystem!"); Debug::log(LOG, "Creating the HookSystem!");
g_pHookSystem = std::make_unique<CHookSystemManager>(); g_pHookSystem = std::make_unique<CHookSystemManager>();
@@ -627,7 +630,7 @@ void CCompositor::startCompositor() {
// This blocks until we are done. // This blocks until we are done.
Debug::log(LOG, "Hyprland is ready, running the event loop!"); Debug::log(LOG, "Hyprland is ready, running the event loop!");
wl_display_run(m_sWLDisplay); g_pEventLoopManager->enterLoop(m_sWLDisplay, m_sWLEventLoop);
} }
CMonitor* CCompositor::getMonitorFromID(const int& id) { CMonitor* CCompositor::getMonitorFromID(const int& id) {
@@ -691,8 +694,10 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
} }
void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) { void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) {
if (windowExists(pWindow) && !pWindow->m_bFadingOut) if (windowExists(pWindow) && !pWindow->m_bFadingOut) {
std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; }); std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; });
std::erase_if(m_vWindowsFadingOut, [&](CWindow* el) { return el == pWindow; });
}
} }
bool CCompositor::windowExists(CWindow* pWindow) { bool CCompositor::windowExists(CWindow* pWindow) {
@@ -701,6 +706,11 @@ bool CCompositor::windowExists(CWindow* pWindow) {
return true; return true;
} }
// FIXME: this is here only temporarily,
// remove this func altogether if no reports
// of this being hit.
RASSERT(!pWindow, "windowExists: attempted UAF");
return false; return false;
} }
@@ -743,20 +753,20 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
auto floating = [&](bool aboveFullscreen) -> CWindow* { auto floating = [&](bool aboveFullscreen) -> CWindow* {
for (auto& w : m_vWindows | std::views::reverse) { for (auto& w : m_vWindows | std::views::reverse) {
if (special && !isWorkspaceSpecial(w->m_iWorkspaceID)) // because special floating may creep up into regular if (special && !w->onSpecialWorkspace()) // because special floating may creep up into regular
continue; continue;
const auto BB = w->getWindowBoxUnified(properties); const auto BB = w->getWindowBoxUnified(properties);
const auto PWINDOWMONITOR = getMonitorFromID(w->m_iMonitorID); const auto PWINDOWMONITOR = getMonitorFromID(w->m_iMonitorID);
// to avoid focusing windows behind special workspaces from other monitors // to avoid focusing windows behind special workspaces from other monitors
if (!*PSPECIALFALLTHRU && PWINDOWMONITOR && PWINDOWMONITOR->specialWorkspaceID && w->m_iWorkspaceID != PWINDOWMONITOR->specialWorkspaceID && if (!*PSPECIALFALLTHRU && PWINDOWMONITOR && PWINDOWMONITOR->activeSpecialWorkspace && w->m_pWorkspace != PWINDOWMONITOR->activeSpecialWorkspace &&
BB.x >= PWINDOWMONITOR->vecPosition.x && BB.y >= PWINDOWMONITOR->vecPosition.y && BB.x >= PWINDOWMONITOR->vecPosition.x && BB.y >= PWINDOWMONITOR->vecPosition.y &&
BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y)
continue; continue;
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA}; CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus &&
w.get() != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { w.get() != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
// OR windows should add focus to parent // OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2) if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
@@ -793,7 +803,7 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
if (properties & FLOATING_ONLY) if (properties & FLOATING_ONLY)
return floating(false); return floating(false);
const int64_t WORKSPACEID = special ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace; const int64_t WORKSPACEID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID();
const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID); const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID);
if (PWORKSPACE->m_bHasFullscreenWindow) if (PWORKSPACE->m_bHasFullscreenWindow)
@@ -805,10 +815,10 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
// for windows, we need to check their extensions too, first. // for windows, we need to check their extensions too, first.
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (special != isWorkspaceSpecial(w->m_iWorkspaceID)) if (special != w->onSpecialWorkspace())
continue; continue;
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w.get() != pIgnoreWindow) { !w->m_sAdditionalConfigData.noFocus && w.get() != pIgnoreWindow) {
if (w->hasPopupAt(pos)) if (w->hasPopupAt(pos))
return w.get(); return w.get();
@@ -816,11 +826,11 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
} }
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (special != isWorkspaceSpecial(w->m_iWorkspaceID)) if (special != w->onSpecialWorkspace())
continue; continue;
CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize};
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w.get() != pIgnoreWindow) !w->m_sAdditionalConfigData.noFocus && w.get() != pIgnoreWindow)
return w.get(); return w.get();
} }
@@ -829,10 +839,10 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
}; };
// special workspace // special workspace
if (PMONITOR->specialWorkspaceID && !*PSPECIALFALLTHRU) if (PMONITOR->activeSpecialWorkspace && !*PSPECIALFALLTHRU)
return windowForWorkspace(true); return windowForWorkspace(true);
if (PMONITOR->specialWorkspaceID) { if (PMONITOR->activeSpecialWorkspace) {
const auto PWINDOW = windowForWorkspace(true); const auto PWINDOW = windowForWorkspace(true);
if (PWINDOW) if (PWINDOW)
@@ -989,15 +999,18 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
return; return;
if (pWindow->m_bPinned) if (pWindow->m_bPinned)
pWindow->m_iWorkspaceID = m_pLastMonitor->activeWorkspace; pWindow->m_pWorkspace = m_pLastMonitor->activeWorkspace;
const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID);
if (!isWorkspaceVisible(pWindow->m_iWorkspaceID)) { if (!isWorkspaceVisible(pWindow->m_pWorkspace)) {
const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = pWindow->m_pWorkspace;
// This is to fix incorrect feedback on the focus history. // This is to fix incorrect feedback on the focus history.
PWORKSPACE->m_pLastFocusedWindow = pWindow; PWORKSPACE->m_pLastFocusedWindow = pWindow;
PWORKSPACE->rememberPrevWorkspace(getWorkspaceByID(m_pLastMonitor->activeWorkspace)); PWORKSPACE->rememberPrevWorkspace(m_pLastMonitor->activeWorkspace);
if (PWORKSPACE->m_bIsSpecialWorkspace)
m_pLastMonitor->changeWorkspace(PWORKSPACE, false, true); // if special ws, open on current monitor
else
PMONITOR->changeWorkspace(PWORKSPACE, false, true); PMONITOR->changeWorkspace(PWORKSPACE, false, true);
// changeworkspace already calls focusWindow // changeworkspace already calls focusWindow
return; return;
@@ -1008,7 +1021,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
/* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which /* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which
window focuses are "via keybinds" and which ones aren't. */ window focuses are "via keybinds" and which ones aren't. */
if (PMONITOR->specialWorkspaceID && PMONITOR->specialWorkspaceID != pWindow->m_iWorkspaceID && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH) if (PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace != pWindow->m_pWorkspace && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window // we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
@@ -1143,13 +1156,34 @@ bool CCompositor::windowValidMapped(CWindow* pWindow) {
return true; return true;
} }
wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, SLayerSurface** ppLayerSurfaceFound) {
for (auto& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) {
for (auto& ls : lsl | std::views::reverse) {
if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f)
continue;
auto SURFACEAT = wlr_layer_surface_v1_popup_surface_at(ls->layerSurface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y);
if (SURFACEAT) {
if (!pixman_region32_not_empty(&SURFACEAT->input_region))
continue;
*ppLayerSurfaceFound = ls.get();
return SURFACEAT;
}
}
}
return nullptr;
}
wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<std::unique_ptr<SLayerSurface>>* layerSurfaces, Vector2D* sCoords, wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<std::unique_ptr<SLayerSurface>>* layerSurfaces, Vector2D* sCoords,
SLayerSurface** ppLayerSurfaceFound) { SLayerSurface** ppLayerSurfaceFound) {
for (auto& ls : *layerSurfaces | std::views::reverse) { for (auto& ls : *layerSurfaces | std::views::reverse) {
if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f)
continue; continue;
auto SURFACEAT = wlr_layer_surface_v1_surface_at(ls->layerSurface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y); auto SURFACEAT = wlr_surface_surface_at(ls->layerSurface->surface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y);
if (SURFACEAT) { if (SURFACEAT) {
if (!pixman_region32_not_empty(&SURFACEAT->input_region)) if (!pixman_region32_not_empty(&SURFACEAT->input_region))
@@ -1163,21 +1197,6 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
return nullptr; return nullptr;
} }
SIMEPopup* CCompositor::vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopup>& popups) {
for (auto& popup : popups) {
auto surface = popup.pSurface->surface;
CBox box{
popup.realX,
popup.realY,
surface->current.width,
surface->current.height,
};
if (box.containsPoint(pos))
return &popup;
}
return nullptr;
}
CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) { CWindow* CCompositor::getWindowFromSurface(wlr_surface* pSurface) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_bFadingOut) if (!w->m_bIsMapped || w->m_bFadingOut)
@@ -1219,29 +1238,21 @@ CWindow* CCompositor::getWindowFromZWLRHandle(wl_resource* handle) {
CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == ID && w->m_bIsFullscreen) if (w->workspaceID() == ID && w->m_bIsFullscreen)
return w.get(); return w.get();
} }
return nullptr; return nullptr;
} }
bool CCompositor::isWorkspaceVisible(const int& w) { bool CCompositor::isWorkspaceVisible(PHLWORKSPACE w) {
for (auto& m : m_vMonitors) { return valid(w) && w->m_bVisible;
if (m->activeWorkspace == w)
return true;
if (m->specialWorkspaceID == w)
return true;
} }
return false; PHLWORKSPACE CCompositor::getWorkspaceByID(const int& id) {
}
CWorkspace* CCompositor::getWorkspaceByID(const int& id) {
for (auto& w : m_vWorkspaces) { for (auto& w : m_vWorkspaces) {
if (w->m_iID == id) if (w->m_iID == id && !w->inert())
return w.get(); return w;
} }
return nullptr; return nullptr;
@@ -1250,50 +1261,32 @@ CWorkspace* CCompositor::getWorkspaceByID(const int& id) {
void CCompositor::sanityCheckWorkspaces() { void CCompositor::sanityCheckWorkspaces() {
auto it = m_vWorkspaces.begin(); auto it = m_vWorkspaces.begin();
while (it != m_vWorkspaces.end()) { while (it != m_vWorkspaces.end()) {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(it->get());
if (WORKSPACERULE.isPersistent) {
++it;
continue;
}
const auto& WORKSPACE = *it; const auto& WORKSPACE = *it;
const auto WINDOWSONWORKSPACE = getWindowsOnWorkspace(WORKSPACE->m_iID);
if (WINDOWSONWORKSPACE == 0) {
if (!isWorkspaceVisible(WORKSPACE->m_iID)) {
if (WORKSPACE->m_bIsSpecialWorkspace) {
if (WORKSPACE->m_fAlpha.value() > 0.f /* don't abruptly end the fadeout */) {
++it;
continue;
}
const auto PMONITOR = getMonitorFromID(WORKSPACE->m_iMonitorID);
if (PMONITOR && PMONITOR->specialWorkspaceID == WORKSPACE->m_iID)
PMONITOR->setSpecialWorkspace(nullptr);
}
// If ref == 1, only the compositor holds a ref, which means it's inactive and has no mapped windows.
if (!WORKSPACE->m_bPersistent && WORKSPACE.use_count() == 1) {
it = m_vWorkspaces.erase(it); it = m_vWorkspaces.erase(it);
continue; continue;
} }
if (!WORKSPACE->m_bOnCreatedEmptyExecuted) {
if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd)
g_pKeybindManager->spawn(*cmd);
WORKSPACE->m_bOnCreatedEmptyExecuted = true;
}
}
++it; ++it;
} }
} }
int CCompositor::getWindowsOnWorkspace(const int& id) { int CCompositor::getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled) {
int no = 0; int no = 0;
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == id && w->m_bIsMapped) if (w->workspaceID() == id && w->m_bIsMapped && !(onlyTiled.has_value() && !w->m_bIsFloating != onlyTiled.value()))
no++;
}
return no;
}
int CCompositor::getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled) {
int no = 0;
for (auto& w : m_vWindows) {
if (w->workspaceID() == id && w->m_bIsMapped && !(onlyTiled.has_value() && !w->m_bIsFloating != onlyTiled.value()) && w->m_sGroupData.head)
no++; no++;
} }
@@ -1311,7 +1304,7 @@ CWindow* CCompositor::getUrgentWindow() {
bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) { bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == id && w->m_bIsMapped && w->m_bIsUrgent) if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent)
return true; return true;
} }
@@ -1320,7 +1313,7 @@ bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) {
CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) { CWindow* CCompositor::getFirstWindowOnWorkspace(const int& id) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == id && w->m_bIsMapped && !w->isHidden()) if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden())
return w.get(); return w.get();
} }
@@ -1336,7 +1329,7 @@ CWindow* CCompositor::getTopLeftWindowOnWorkspace(const int& id) {
const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID); const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID);
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID != id || !w->m_bIsMapped || w->isHidden()) if (w->workspaceID() != id || !w->m_bIsMapped || w->isHidden())
continue; continue;
const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
@@ -1372,7 +1365,7 @@ bool CCompositor::isWindowActive(CWindow* pWindow) {
if (!m_pLastWindow && !m_pLastFocus) if (!m_pLastWindow && !m_pLastFocus)
return false; return false;
if (!windowValidMapped(pWindow)) if (!pWindow->m_bIsMapped)
return false; return false;
const auto PSURFACE = pWindow->m_pWLSurface.wlr(); const auto PSURFACE = pWindow->m_pWLSurface.wlr();
@@ -1443,19 +1436,14 @@ void CCompositor::cleanupFadingOut(const int& monid) {
if (w->m_iMonitorID != (long unsigned int)monid) if (w->m_iMonitorID != (long unsigned int)monid)
continue; continue;
bool valid = windowExists(w); if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) {
if (!valid || !w->m_bFadingOut || w->m_fAlpha.value() == 0.f) {
if (valid) {
w->m_bFadingOut = false; w->m_bFadingOut = false;
if (!w->m_bReadyToDelete) if (!w->m_bReadyToDelete)
continue; continue;
removeWindowFromVectorSafe(w); removeWindowFromVectorSafe(w);
}
std::erase(m_vWindowsFadingOut, w);
Debug::log(LOG, "Cleanup: destroyed a window"); Debug::log(LOG, "Cleanup: destroyed a window");
return; return;
@@ -1554,7 +1542,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y); const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y);
const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height); const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = pWindow->m_pWorkspace;
auto leaderValue = -1; auto leaderValue = -1;
CWindow* leaderWindow = nullptr; CWindow* leaderWindow = nullptr;
@@ -1562,10 +1550,10 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
// for tiled windows, we calc edges // for tiled windows, we calc edges
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID)) if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->m_bIsFullscreen && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace))
continue; continue;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID) if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace)
continue; continue;
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen)
@@ -1651,10 +1639,10 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
constexpr float THRESHOLD = 0.3 * M_PI; constexpr float THRESHOLD = 0.3 * M_PI;
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || !w->m_bIsFloating || !isWorkspaceVisible(w->m_iWorkspaceID)) if (w.get() == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->m_bIsFullscreen && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace))
continue; continue;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID) if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace)
continue; continue;
if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen)
@@ -1697,7 +1685,7 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value()) if (floating.has_value() && w->m_bIsFloating != floating.value())
continue; continue;
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get(); return w.get();
} }
@@ -1705,7 +1693,7 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value()) if (floating.has_value() && w->m_bIsFloating != floating.value())
continue; continue;
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) if (w.get() != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get(); return w.get();
} }
@@ -1726,7 +1714,7 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value()) if (floating.has_value() && w->m_bIsFloating != floating.value())
continue; continue;
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get(); return w.get();
} }
@@ -1734,7 +1722,7 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value()) if (floating.has_value() && w->m_bIsFloating != floating.value())
continue; continue;
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) if (w.get() != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get(); return w.get();
} }
@@ -1751,16 +1739,16 @@ int CCompositor::getNextAvailableNamedWorkspace() {
return lowest - 1; return lowest - 1;
} }
CWorkspace* CCompositor::getWorkspaceByName(const std::string& name) { PHLWORKSPACE CCompositor::getWorkspaceByName(const std::string& name) {
for (auto& w : m_vWorkspaces) { for (auto& w : m_vWorkspaces) {
if (w->m_szName == name) if (w->m_szName == name && !w->inert())
return w.get(); return w;
} }
return nullptr; return nullptr;
} }
CWorkspace* CCompositor::getWorkspaceByString(const std::string& str) { PHLWORKSPACE CCompositor::getWorkspaceByString(const std::string& str) {
if (str.starts_with("name:")) { if (str.starts_with("name:")) {
return getWorkspaceByName(str.substr(str.find_first_of(':') + 1)); return getWorkspaceByName(str.substr(str.find_first_of(':') + 1));
} }
@@ -1875,7 +1863,7 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() {
void CCompositor::updateWorkspaceWindows(const int64_t& id) { void CCompositor::updateWorkspaceWindows(const int64_t& id) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_iWorkspaceID != id) if (!w->m_bIsMapped || w->workspaceID() != id)
continue; continue;
w->updateDynamicRules(); w->updateDynamicRules();
@@ -1943,9 +1931,12 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
pWindow->m_fBorderAngleAnimationProgress.setValueAndWarp(0.f); pWindow->m_fBorderAngleAnimationProgress.setValueAndWarp(0.f);
// opacity // opacity
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = pWindow->m_pWorkspace;
if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
pWindow->m_fActiveInactiveAlpha = *PFULLSCREENALPHA; pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() != -1 ?
(pWindow->m_sSpecialRenderData.alphaFullscreenOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() :
pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() * *PFULLSCREENALPHA) :
*PFULLSCREENALPHA;
} else { } else {
if (pWindow == m_pLastWindow) if (pWindow == m_pLastWindow)
pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alpha.toUnderlying() : pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alpha.toUnderlying() :
@@ -1999,16 +1990,16 @@ int CCompositor::getNextAvailableMonitorID(std::string const& name) {
void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) { void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) {
const auto PWORKSPACEA = g_pCompositor->getWorkspaceByID(pMonitorA->activeWorkspace); const auto PWORKSPACEA = pMonitorA->activeWorkspace;
const auto PWORKSPACEB = g_pCompositor->getWorkspaceByID(pMonitorB->activeWorkspace); const auto PWORKSPACEB = pMonitorB->activeWorkspace;
PWORKSPACEA->m_iMonitorID = pMonitorB->ID; PWORKSPACEA->m_iMonitorID = pMonitorB->ID;
PWORKSPACEA->moveToMonitor(pMonitorB->ID); PWORKSPACEA->moveToMonitor(pMonitorB->ID);
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == PWORKSPACEA->m_iID) { if (w->m_pWorkspace == PWORKSPACEA) {
if (w->m_bPinned) { if (w->m_bPinned) {
w->m_iWorkspaceID = PWORKSPACEB->m_iID; w->m_pWorkspace = PWORKSPACEB;
continue; continue;
} }
@@ -2016,7 +2007,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
// additionally, move floating and fs windows manually // additionally, move floating and fs windows manually
if (w->m_bIsFloating) if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.value() - pMonitorA->vecPosition + pMonitorB->vecPosition; w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorA->vecPosition + pMonitorB->vecPosition;
if (w->m_bIsFullscreen) { if (w->m_bIsFullscreen) {
w->m_vRealPosition = pMonitorB->vecPosition; w->m_vRealPosition = pMonitorB->vecPosition;
@@ -2031,9 +2022,9 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
PWORKSPACEB->moveToMonitor(pMonitorA->ID); PWORKSPACEB->moveToMonitor(pMonitorA->ID);
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == PWORKSPACEB->m_iID) { if (w->m_pWorkspace == PWORKSPACEB) {
if (w->m_bPinned) { if (w->m_bPinned) {
w->m_iWorkspaceID = PWORKSPACEA->m_iID; w->m_pWorkspace = PWORKSPACEA;
continue; continue;
} }
@@ -2041,7 +2032,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
// additionally, move floating and fs windows manually // additionally, move floating and fs windows manually
if (w->m_bIsFloating) if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.value() - pMonitorB->vecPosition + pMonitorA->vecPosition; w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorB->vecPosition + pMonitorA->vecPosition;
if (w->m_bIsFullscreen) { if (w->m_bIsFullscreen) {
w->m_vRealPosition = pMonitorA->vecPosition; w->m_vRealPosition = pMonitorA->vecPosition;
@@ -2052,8 +2043,8 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
} }
} }
pMonitorA->activeWorkspace = PWORKSPACEB->m_iID; pMonitorA->activeWorkspace = PWORKSPACEB;
pMonitorB->activeWorkspace = PWORKSPACEA->m_iID; pMonitorB->activeWorkspace = PWORKSPACEA;
PWORKSPACEA->rememberPrevWorkspace(PWORKSPACEB); PWORKSPACEA->rememberPrevWorkspace(PWORKSPACEB);
PWORKSPACEB->rememberPrevWorkspace(PWORKSPACEA); PWORKSPACEB->rememberPrevWorkspace(PWORKSPACEA);
@@ -2068,15 +2059,20 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
const auto LASTWIN = pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID ? PWORKSPACEB->getLastFocusedWindow() : PWORKSPACEA->getLastFocusedWindow(); const auto LASTWIN = pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID ? PWORKSPACEB->getLastFocusedWindow() : PWORKSPACEA->getLastFocusedWindow();
g_pCompositor->focusWindow(LASTWIN ? LASTWIN : g_pCompositor->focusWindow(LASTWIN ? LASTWIN :
(g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING))); (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING)));
const auto PNEWWORKSPACE = pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID ? PWORKSPACEB : PWORKSPACEA;
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PNEWWORKSPACE->m_szName});
g_pEventManager->postEvent(SHyprIPCEvent{"workspacev2", std::format("{},{}", PNEWWORKSPACE->m_iID, PNEWWORKSPACE->m_szName)});
EMIT_HOOK_EVENT("workspace", PNEWWORKSPACE);
} }
// event // event
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName});
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEA->m_iID, PWORKSPACEA->m_szName, pMonitorB->szName)}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEA->m_iID, PWORKSPACEA->m_szName, pMonitorB->szName)});
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<void*>{PWORKSPACEA, pMonitorB})); EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{PWORKSPACEA, pMonitorB}));
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEB->m_szName + "," + pMonitorA->szName}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEB->m_szName + "," + pMonitorA->szName});
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEB->m_iID, PWORKSPACEB->m_szName, pMonitorA->szName)}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEB->m_iID, PWORKSPACEB->m_szName, pMonitorA->szName)});
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<void*>{PWORKSPACEB, pMonitorA})); EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{PWORKSPACEB, pMonitorA}));
} }
CMonitor* CCompositor::getMonitorFromString(const std::string& name) { CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
@@ -2153,9 +2149,9 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
return nullptr; return nullptr;
} }
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor, bool noWarpCursor) { void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMonitor, bool noWarpCursor) {
// We trust the workspace and monitor to be correct. // We trust the monitor to be correct.
if (pWorkspace->m_iMonitorID == pMonitor->ID) if (pWorkspace->m_iMonitorID == pMonitor->ID)
return; return;
@@ -2164,7 +2160,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
const auto POLDMON = getMonitorFromID(pWorkspace->m_iMonitorID); const auto POLDMON = getMonitorFromID(pWorkspace->m_iMonitorID);
const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace->m_iID : false; const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace : false;
// fix old mon // fix old mon
int nextWorkspaceOnMonitorID = -1; int nextWorkspaceOnMonitorID = -1;
@@ -2201,9 +2197,9 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
pWorkspace->moveToMonitor(pMonitor->ID); pWorkspace->moveToMonitor(pMonitor->ID);
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == pWorkspace->m_iID) { if (w->m_pWorkspace == pWorkspace) {
if (w->m_bPinned) { if (w->m_bPinned) {
w->m_iWorkspaceID = nextWorkspaceOnMonitorID; w->m_pWorkspace = g_pCompositor->getWorkspaceByID(nextWorkspaceOnMonitorID);
continue; continue;
} }
@@ -2213,7 +2209,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
if (w->m_bIsMapped && !w->isHidden()) { if (w->m_bIsMapped && !w->isHidden()) {
if (POLDMON) { if (POLDMON) {
if (w->m_bIsFloating) if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.value() - POLDMON->vecPosition + pMonitor->vecPosition; w->m_vRealPosition = w->m_vRealPosition.goal() - POLDMON->vecPosition + pMonitor->vecPosition;
if (w->m_bIsFullscreen) { if (w->m_bIsFullscreen) {
w->m_vRealPosition = pMonitor->vecPosition; w->m_vRealPosition = pMonitor->vecPosition;
@@ -2229,16 +2225,19 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
} }
if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor) { // if it was active, preserve its' status. If it wasn't, don't. if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor) { // if it was active, preserve its' status. If it wasn't, don't.
Debug::log(LOG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {}", pMonitor->activeWorkspace, pWorkspace->m_iID); Debug::log(LOG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {}", pMonitor->activeWorkspaceID(), pWorkspace->m_iID);
if (const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace); PWORKSPACE) if (valid(pMonitor->activeWorkspace)) {
getWorkspaceByID(pMonitor->activeWorkspace)->startAnim(false, false); pMonitor->activeWorkspace->m_bVisible = false;
pMonitor->activeWorkspace->startAnim(false, false);
}
setActiveMonitor(pMonitor); setActiveMonitor(pMonitor);
pMonitor->activeWorkspace = pWorkspace->m_iID; pMonitor->activeWorkspace = pWorkspace;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
pWorkspace->startAnim(true, true, true); pWorkspace->startAnim(true, true, true);
pWorkspace->m_bVisible = true;
if (!noWarpCursor) if (!noWarpCursor)
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2); wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
@@ -2249,7 +2248,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
// finalize // finalize
if (POLDMON) { if (POLDMON) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
updateFullscreenFadeOnWorkspace(getWorkspaceByID(POLDMON->activeWorkspace)); updateFullscreenFadeOnWorkspace(POLDMON->activeWorkspace);
} }
updateFullscreenFadeOnWorkspace(pWorkspace); updateFullscreenFadeOnWorkspace(pWorkspace);
@@ -2257,7 +2256,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
// event // event
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", pWorkspace->m_szName + "," + pMonitor->szName}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", pWorkspace->m_szName + "," + pMonitor->szName});
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", pWorkspace->m_iID, pWorkspace->m_szName, pMonitor->szName)}); g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", pWorkspace->m_iID, pWorkspace->m_szName, pMonitor->szName)});
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<void*>{pWorkspace, pMonitor})); EMIT_HOOK_EVENT("moveWorkspace", (std::vector<std::any>{pWorkspace, pMonitor}));
} }
bool CCompositor::workspaceIDOutOfBounds(const int64_t& id) { bool CCompositor::workspaceIDOutOfBounds(const int64_t& id) {
@@ -2278,12 +2277,12 @@ bool CCompositor::workspaceIDOutOfBounds(const int64_t& id) {
return std::clamp(id, lowestID, highestID) != id; return std::clamp(id, lowestID, highestID) != id;
} }
void CCompositor::updateFullscreenFadeOnWorkspace(CWorkspace* pWorkspace) { void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) {
const auto FULLSCREEN = pWorkspace->m_bHasFullscreenWindow; const auto FULLSCREEN = pWorkspace->m_bHasFullscreenWindow;
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWorkspace->m_iID) { if (w->m_pWorkspace == pWorkspace) {
if (w->m_bFadingOut || w->m_bPinned || w->m_bIsFullscreen) if (w->m_bFadingOut || w->m_bPinned || w->m_bIsFullscreen)
continue; continue;
@@ -2297,7 +2296,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(CWorkspace* pWorkspace) {
const auto PMONITOR = getMonitorFromID(pWorkspace->m_iMonitorID); const auto PMONITOR = getMonitorFromID(pWorkspace->m_iMonitorID);
if (pWorkspace->m_iID == PMONITOR->activeWorkspace || pWorkspace->m_iID == PMONITOR->specialWorkspaceID) { if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) {
for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
if (!ls->fadingOut) if (!ls->fadingOut)
ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 1.f; ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 1.f;
@@ -2321,7 +2320,7 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID);
const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = pWindow->m_pWorkspace;
const auto MODE = mode == FULLSCREEN_INVALID ? PWORKSPACE->m_efFullscreenMode : mode; const auto MODE = mode == FULLSCREEN_INVALID ? PWORKSPACE->m_efFullscreenMode : mode;
@@ -2338,14 +2337,14 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
// make all windows on the same workspace under the fullscreen window // make all windows on the same workspace under the fullscreen window
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == PWORKSPACE->m_iID && !w->m_bIsFullscreen && !w->m_bFadingOut && !w->m_bPinned) if (w->m_pWorkspace == PWORKSPACE && !w->m_bIsFullscreen && !w->m_bFadingOut && !w->m_bPinned)
w->m_bCreatedOverFullscreen = false; w->m_bCreatedOverFullscreen = false;
} }
updateFullscreenFadeOnWorkspace(PWORKSPACE); updateFullscreenFadeOnWorkspace(PWORKSPACE);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal(), true); g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal(), true);
forceReportSizesToWindowsOnWorkspace(pWindow->m_iWorkspaceID); forceReportSizesToWindowsOnWorkspace(pWindow->workspaceID());
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
@@ -2372,13 +2371,25 @@ CWindow* CCompositor::getX11Parent(CWindow* pWindow) {
void CCompositor::updateWorkspaceWindowDecos(const int& id) { void CCompositor::updateWorkspaceWindowDecos(const int& id) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID != id) if (w->workspaceID() != id)
continue; continue;
w->updateWindowDecos(); w->updateWindowDecos();
} }
} }
void CCompositor::updateWorkspaceSpecialRenderData(const int& id) {
const auto PWORKSPACE = getWorkspaceByID(id);
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
for (auto& w : m_vWindows) {
if (w->workspaceID() != id)
continue;
w->updateSpecialRenderData(WORKSPACERULE);
}
}
void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) { void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive) if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
return; return;
@@ -2414,7 +2425,7 @@ CWindow* CCompositor::getWindowByRegex(const std::string& regexp) {
const bool FLOAT = regexp.starts_with("floating"); const bool FLOAT = regexp.starts_with("floating");
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_iWorkspaceID != m_pLastWindow->m_iWorkspaceID || w->isHidden()) if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden())
continue; continue;
return w.get(); return w.get();
@@ -2532,7 +2543,7 @@ SLayerSurface* CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) {
// returns a delta // returns a delta
Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, const Vector2D& relativeTo) { Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, const Vector2D& relativeTo) {
if (!args.contains(' ')) if (!args.contains(' ') && !args.contains('\t'))
return relativeTo; return relativeTo;
const auto PMONITOR = m_pLastMonitor; const auto PMONITOR = m_pLastMonitor;
@@ -2541,12 +2552,13 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
bool yIsPercent = false; bool yIsPercent = false;
bool isExact = false; bool isExact = false;
std::string x = args.substr(0, args.find_first_of(' ')); CVarList varList(args, 0, 's', true);
std::string y = args.substr(args.find_first_of(' ') + 1); std::string x = varList[0];
std::string y = varList[1];
if (x == "exact") { if (x == "exact") {
x = y.substr(0, y.find_first_of(' ')); x = varList[1];
y = y.substr(y.find_first_of(' ') + 1); y = varList[2];
isExact = true; isExact = true;
} }
@@ -2581,13 +2593,13 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) { void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == wid && w->m_bIsMapped && !w->isHidden()) { if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) {
g_pXWaylandManager->setWindowSize(w.get(), w->m_vRealSize.value(), true); g_pXWaylandManager->setWindowSize(w.get(), w->m_vRealSize.value(), true);
} }
} }
} }
CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name) { PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name) {
const auto NAME = name == "" ? std::to_string(id) : name; const auto NAME = name == "" ? std::to_string(id) : name;
auto monID = monid; auto monID = monid;
@@ -2598,7 +2610,7 @@ CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, con
const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2; const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2;
const auto PWORKSPACE = m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(id, monID, NAME, SPECIAL)).get(); const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, monID, NAME, SPECIAL));
PWORKSPACE->m_fAlpha.setValueAndWarp(0); PWORKSPACE->m_fAlpha.setValueAndWarp(0);
@@ -2629,7 +2641,7 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
return; return;
} }
const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace); const auto PWORKSPACE = pMonitor->activeWorkspace;
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + (PWORKSPACE ? PWORKSPACE->m_szName : "?")}); g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + (PWORKSPACE ? PWORKSPACE->m_szName : "?")});
EMIT_HOOK_EVENT("focusedMon", pMonitor); EMIT_HOOK_EVENT("focusedMon", pMonitor);
@@ -2655,7 +2667,7 @@ void CCompositor::performUserChecks() {
; // intentional ; // intentional
} }
void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) { void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, PHLWORKSPACE pWorkspace) {
if (!pWindow || !pWorkspace) if (!pWindow || !pWorkspace)
return; return;
@@ -2663,16 +2675,16 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
return; return;
const bool FULLSCREEN = pWindow->m_bIsFullscreen; const bool FULLSCREEN = pWindow->m_bIsFullscreen;
const auto FULLSCREENMODE = getWorkspaceByID(pWindow->m_iWorkspaceID)->m_efFullscreenMode; const auto FULLSCREENMODE = pWindow->m_pWorkspace->m_efFullscreenMode;
if (FULLSCREEN) if (FULLSCREEN)
setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
pWindow->moveToWorkspace(pWorkspace->m_iID); pWindow->moveToWorkspace(pWorkspace);
if (!pWindow->m_bIsFloating) { if (!pWindow->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow);
pWindow->m_iWorkspaceID = pWorkspace->m_iID; pWindow->m_pWorkspace = pWorkspace;
pWindow->m_iMonitorID = pWorkspace->m_iMonitorID; pWindow->m_iMonitorID = pWorkspace->m_iMonitorID;
g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(pWindow); g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(pWindow);
} else { } else {
@@ -2681,7 +2693,7 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
const auto PWORKSPACEMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); const auto PWORKSPACEMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
pWindow->m_iWorkspaceID = pWorkspace->m_iID; pWindow->m_pWorkspace = pWorkspace;
pWindow->m_iMonitorID = pWorkspace->m_iMonitorID; pWindow->m_iMonitorID = pWorkspace->m_iMonitorID;
pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition; pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition;
@@ -2694,7 +2706,7 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
if (pWindow->m_sGroupData.pNextWindow) { if (pWindow->m_sGroupData.pNextWindow) {
CWindow* next = pWindow->m_sGroupData.pNextWindow; CWindow* next = pWindow->m_sGroupData.pNextWindow;
while (next != pWindow) { while (next != pWindow) {
next->moveToWorkspace(pWorkspace->m_iID); next->moveToWorkspace(pWorkspace);
next->updateToplevel(); next->updateToplevel();
next = next->m_sGroupData.pNextWindow; next = next->m_sGroupData.pNextWindow;
} }
@@ -2704,12 +2716,12 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
setWindowFullscreen(pWindow, true, FULLSCREENMODE); setWindowFullscreen(pWindow, true, FULLSCREENMODE);
g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID); g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID);
g_pCompositor->updateWorkspaceWindows(pWindow->m_iWorkspaceID); g_pCompositor->updateWorkspaceWindows(pWindow->workspaceID());
} }
CWindow* CCompositor::getForceFocus() { CWindow* CCompositor::getForceFocus() {
for (auto& w : m_vWindows) { for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->isHidden() || !isWorkspaceVisible(w->m_iWorkspaceID)) if (!w->m_bIsMapped || w->isHidden() || !isWorkspaceVisible(w->m_pWorkspace))
continue; continue;
if (!w->m_bStayFocused) if (!w->m_bStayFocused)
@@ -2797,6 +2809,8 @@ void CCompositor::enterUnsafeState() {
m_pUnsafeOutput->onConnect(false); m_pUnsafeOutput->onConnect(false);
m_bUnsafeState = true; m_bUnsafeState = true;
setActiveMonitor(m_pUnsafeOutput);
} }
void CCompositor::leaveUnsafeState() { void CCompositor::leaveUnsafeState() {
@@ -2856,6 +2870,6 @@ void CCompositor::updateSuspendedStates() {
if (!w->m_bIsMapped) if (!w->m_bIsMapped)
continue; continue;
w->setSuspended(w->isHidden() || !isWorkspaceVisible(w->m_iWorkspaceID)); w->setSuspended(w->isHidden() || !isWorkspaceVisible(w->m_pWorkspace));
} }
} }

View File

@@ -22,7 +22,7 @@
#include "debug/HyprNotificationOverlay.hpp" #include "debug/HyprNotificationOverlay.hpp"
#include "helpers/Monitor.hpp" #include "helpers/Monitor.hpp"
#include "desktop/Workspace.hpp" #include "desktop/Workspace.hpp"
#include "Window.hpp" #include "desktop/Window.hpp"
#include "render/Renderer.hpp" #include "render/Renderer.hpp"
#include "render/OpenGL.hpp" #include "render/OpenGL.hpp"
#include "hyprerror/HyprError.hpp" #include "hyprerror/HyprError.hpp"
@@ -92,7 +92,7 @@ class CCompositor {
std::vector<std::shared_ptr<CMonitor>> m_vMonitors; std::vector<std::shared_ptr<CMonitor>> m_vMonitors;
std::vector<std::shared_ptr<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off std::vector<std::shared_ptr<CMonitor>> m_vRealMonitors; // for all monitors, even those turned off
std::vector<std::unique_ptr<CWindow>> m_vWindows; std::vector<std::unique_ptr<CWindow>> m_vWindows;
std::vector<std::unique_ptr<CWorkspace>> m_vWorkspaces; std::vector<PHLWORKSPACE> m_vWorkspaces;
std::vector<CWindow*> m_vWindowsFadingOut; std::vector<CWindow*> m_vWindowsFadingOut;
std::vector<SLayerSurface*> m_vSurfacesFadingOut; std::vector<SLayerSurface*> m_vSurfacesFadingOut;
@@ -118,6 +118,7 @@ class CCompositor {
bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; // because wlroots bool m_bNextIsUnsafe = false; // because wlroots
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bExitTriggered = false; // For exit dispatcher
bool m_bIsShuttingDown = false; bool m_bIsShuttingDown = false;
// ------------------------------------------------- // // ------------------------------------------------- //
@@ -135,7 +136,7 @@ class CCompositor {
bool monitorExists(CMonitor*); bool monitorExists(CMonitor*);
CWindow* vectorToWindowUnified(const Vector2D&, uint8_t properties, CWindow* pIgnoreWindow = nullptr); CWindow* vectorToWindowUnified(const Vector2D&, uint8_t properties, CWindow* pIgnoreWindow = nullptr);
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**); wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
SIMEPopup* vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopup>& popups); wlr_surface* vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, SLayerSurface**);
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl); wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*); Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
CMonitor* getMonitorFromOutput(wlr_output*); CMonitor* getMonitorFromOutput(wlr_output*);
@@ -143,13 +144,15 @@ class CCompositor {
CWindow* getWindowFromSurface(wlr_surface*); CWindow* getWindowFromSurface(wlr_surface*);
CWindow* getWindowFromHandle(uint32_t); CWindow* getWindowFromHandle(uint32_t);
CWindow* getWindowFromZWLRHandle(wl_resource*); CWindow* getWindowFromZWLRHandle(wl_resource*);
bool isWorkspaceVisible(const int&); bool isWorkspaceVisible(PHLWORKSPACE);
CWorkspace* getWorkspaceByID(const int&); PHLWORKSPACE getWorkspaceByID(const int&);
CWorkspace* getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByName(const std::string&);
CWorkspace* getWorkspaceByString(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces(); void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&); void updateWorkspaceWindowDecos(const int&);
int getWindowsOnWorkspace(const int&); void updateWorkspaceSpecialRenderData(const int&);
int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {});
int getGroupsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {});
CWindow* getUrgentWindow(); CWindow* getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const int&); bool hasUrgentWindowOnWorkspace(const int&);
CWindow* getFirstWindowOnWorkspace(const int&); CWindow* getFirstWindowOnWorkspace(const int&);
@@ -171,12 +174,12 @@ class CCompositor {
void updateWorkspaceWindows(const int64_t& id); void updateWorkspaceWindows(const int64_t& id);
void updateWindowAnimatedDecorationValues(CWindow*); void updateWindowAnimatedDecorationValues(CWindow*);
int getNextAvailableMonitorID(std::string const& name); int getNextAvailableMonitorID(std::string const& name);
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*, bool noWarpCursor = false); void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false);
void swapActiveWorkspaces(CMonitor*, CMonitor*); void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&); CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&); bool workspaceIDOutOfBounds(const int64_t&);
void setWindowFullscreen(CWindow*, bool, eFullscreenMode mode = FULLSCREEN_INVALID); void setWindowFullscreen(CWindow*, bool, eFullscreenMode mode = FULLSCREEN_INVALID);
void updateFullscreenFadeOnWorkspace(CWorkspace*); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE);
CWindow* getX11Parent(CWindow*); CWindow* getX11Parent(CWindow*);
void scheduleFrameForMonitor(CMonitor*); void scheduleFrameForMonitor(CMonitor*);
void addToFadingOutSafe(SLayerSurface*); void addToFadingOutSafe(SLayerSurface*);
@@ -188,13 +191,13 @@ class CCompositor {
void closeWindow(CWindow*); void closeWindow(CWindow*);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void forceReportSizesToWindowsOnWorkspace(const int&); void forceReportSizesToWindowsOnWorkspace(const int&);
CWorkspace* createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused! PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused!
void renameWorkspace(const int&, const std::string& name = ""); void renameWorkspace(const int&, const std::string& name = "");
void setActiveMonitor(CMonitor*); void setActiveMonitor(CMonitor*);
bool isWorkspaceSpecial(const int&); bool isWorkspaceSpecial(const int&);
int getNewSpecialID(); int getNewSpecialID();
void performUserChecks(); void performUserChecks();
void moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace); void moveWindowToWorkspaceSafe(CWindow* pWindow, PHLWORKSPACE pWorkspace);
CWindow* getForceFocus(); CWindow* getForceFocus();
void notifyIdleActivity(); void notifyIdleActivity();
void setIdleActivityInhibit(bool inhibit); void setIdleActivityInhibit(bool inhibit);

View File

@@ -70,3 +70,5 @@ struct SHyprCtlCommand {
bool exact = true; bool exact = true;
std::function<std::string(eHyprCtlOutputFormat, std::string)> fn; std::function<std::string(eHyprCtlOutputFormat, std::string)> fn;
}; };
typedef std::function<void(void*, SCallbackInfo&, std::any)> HOOK_CALLBACK_FN;

View File

@@ -61,6 +61,7 @@ class CGradientValueData : public ICustomConfigValueData {
} }
result += std::format("{}deg", (int)(m_fAngle * 180.0 / M_PI)); result += std::format("{}deg", (int)(m_fAngle * 180.0 / M_PI));
return result;
} }
}; };

View File

@@ -349,6 +349,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("misc:background_color", Hyprlang::INT{0xff111111}); m_pConfig->addConfigValue("misc:background_color", Hyprlang::INT{0xff111111});
m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:enable_hyprcursor", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:enable_hyprcursor", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:hide_cursor_on_key_press", Hyprlang::INT{0});
m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1});
m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1});
@@ -372,6 +373,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("debug:damage_tracking", {(Hyprlang::INT)DAMAGE_TRACKING_FULL}); m_pConfig->addConfigValue("debug:damage_tracking", {(Hyprlang::INT)DAMAGE_TRACKING_FULL});
m_pConfig->addConfigValue("debug:manual_crash", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:manual_crash", Hyprlang::INT{0});
m_pConfig->addConfigValue("debug:suppress_errors", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:suppress_errors", Hyprlang::INT{0});
m_pConfig->addConfigValue("debug:error_limit", Hyprlang::INT{5});
m_pConfig->addConfigValue("debug:watchdog_timeout", Hyprlang::INT{5}); m_pConfig->addConfigValue("debug:watchdog_timeout", Hyprlang::INT{5});
m_pConfig->addConfigValue("debug:disable_scale_checks", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:disable_scale_checks", Hyprlang::INT{0});
@@ -438,6 +440,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("input:follow_mouse", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:follow_mouse", Hyprlang::INT{1});
m_pConfig->addConfigValue("input:mouse_refocus", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:mouse_refocus", Hyprlang::INT{1});
m_pConfig->addConfigValue("input:special_fallthrough", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:special_fallthrough", Hyprlang::INT{0});
m_pConfig->addConfigValue("input:off_window_axis_events", Hyprlang::INT{1});
m_pConfig->addConfigValue("input:sensitivity", {0.f}); m_pConfig->addConfigValue("input:sensitivity", {0.f});
m_pConfig->addConfigValue("input:accel_profile", {STRVAL_EMPTY}); m_pConfig->addConfigValue("input:accel_profile", {STRVAL_EMPTY});
m_pConfig->addConfigValue("input:kb_file", {STRVAL_EMPTY}); m_pConfig->addConfigValue("input:kb_file", {STRVAL_EMPTY});
@@ -476,6 +479,9 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("input:tablet:region_position", Hyprlang::VEC2{0, 0}); m_pConfig->addConfigValue("input:tablet:region_position", Hyprlang::VEC2{0, 0});
m_pConfig->addConfigValue("input:tablet:region_size", Hyprlang::VEC2{0, 0}); m_pConfig->addConfigValue("input:tablet:region_size", Hyprlang::VEC2{0, 0});
m_pConfig->addConfigValue("input:tablet:relative_input", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:tablet:relative_input", Hyprlang::INT{0});
m_pConfig->addConfigValue("input:tablet:left_handed", Hyprlang::INT{0});
m_pConfig->addConfigValue("input:tablet:active_area_position", Hyprlang::VEC2{0, 0});
m_pConfig->addConfigValue("input:tablet:active_area_size", Hyprlang::VEC2{0, 0});
m_pConfig->addConfigValue("binds:pass_mouse_when_bound", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:pass_mouse_when_bound", Hyprlang::INT{0});
m_pConfig->addConfigValue("binds:scroll_event_delay", Hyprlang::INT{300}); m_pConfig->addConfigValue("binds:scroll_event_delay", Hyprlang::INT{300});
@@ -485,6 +491,7 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("binds:focus_preferred_method", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:focus_preferred_method", Hyprlang::INT{0});
m_pConfig->addConfigValue("binds:ignore_group_lock", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:ignore_group_lock", Hyprlang::INT{0});
m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", Hyprlang::INT{1}); m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", Hyprlang::INT{1});
m_pConfig->addConfigValue("binds:disable_keybind_grabbing", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_fingers", Hyprlang::INT{3}); m_pConfig->addConfigValue("gestures:workspace_swipe_fingers", Hyprlang::INT{3});
@@ -496,8 +503,8 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("gestures:workspace_swipe_direction_lock", Hyprlang::INT{1}); m_pConfig->addConfigValue("gestures:workspace_swipe_direction_lock", Hyprlang::INT{1});
m_pConfig->addConfigValue("gestures:workspace_swipe_direction_lock_threshold", Hyprlang::INT{10}); m_pConfig->addConfigValue("gestures:workspace_swipe_direction_lock_threshold", Hyprlang::INT{10});
m_pConfig->addConfigValue("gestures:workspace_swipe_forever", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_forever", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_numbered", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_use_r", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_use_r", Hyprlang::INT{0});
m_pConfig->addConfigValue("gestures:workspace_swipe_touch", Hyprlang::INT{0});
m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1}); m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1});
m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0}); m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0});
@@ -555,6 +562,8 @@ CConfigManager::CConfigManager() {
m_pConfig->addSpecialConfigValue("device", "region_position", Hyprlang::VEC2{0, 0}); // only for tablets m_pConfig->addSpecialConfigValue("device", "region_position", Hyprlang::VEC2{0, 0}); // only for tablets
m_pConfig->addSpecialConfigValue("device", "region_size", Hyprlang::VEC2{0, 0}); // only for tablets m_pConfig->addSpecialConfigValue("device", "region_size", Hyprlang::VEC2{0, 0}); // only for tablets
m_pConfig->addSpecialConfigValue("device", "relative_input", Hyprlang::INT{0}); // only for tablets m_pConfig->addSpecialConfigValue("device", "relative_input", Hyprlang::INT{0}); // only for tablets
m_pConfig->addSpecialConfigValue("device", "active_area_position", Hyprlang::VEC2{0, 0}); // only for tablets
m_pConfig->addSpecialConfigValue("device", "active_area_size", Hyprlang::VEC2{0, 0}); // only for tablets
// keywords // keywords
m_pConfig->registerHandler(&::handleRawExec, "exec", {false}); m_pConfig->registerHandler(&::handleRawExec, "exec", {false});
@@ -579,11 +588,13 @@ CConfigManager::CConfigManager() {
m_pConfig->commence(); m_pConfig->commence();
Debug::log(LOG, "NOTE: further logs to stdout / logfile are disabled by default. Use debug:disable_logs and debug:enable_stdout_logs to override this.");
setDefaultAnimationVars(); setDefaultAnimationVars();
resetHLConfig(); resetHLConfig();
Debug::log(LOG,
"!!!!HEY YOU, YES YOU!!!!: further logs to stdout / logfile are disabled by default. BEFORE SENDING THIS LOG, ENABLE THEM. Use debug:disable_logs = false to do so: "
"https://wiki.hyprland.org/Configuring/Variables/#debug");
Debug::disableLogs = reinterpret_cast<int64_t* const*>(m_pConfig->getConfigValuePtr("debug:disable_logs")->getDataStaticPtr()); Debug::disableLogs = reinterpret_cast<int64_t* const*>(m_pConfig->getConfigValuePtr("debug:disable_logs")->getDataStaticPtr());
Debug::disableTime = reinterpret_cast<int64_t* const*>(m_pConfig->getConfigValuePtr("debug:disable_time")->getDataStaticPtr()); Debug::disableTime = reinterpret_cast<int64_t* const*>(m_pConfig->getConfigValuePtr("debug:disable_time")->getDataStaticPtr());
@@ -607,6 +618,10 @@ std::string CConfigManager::getMainConfigPath() {
return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf"); return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf");
} }
std::string CConfigManager::getErrors() {
return m_szConfigErrors;
}
void CConfigManager::reload() { void CConfigManager::reload() {
EMIT_HOOK_EVENT("preConfigReload", nullptr); EMIT_HOOK_EVENT("preConfigReload", nullptr);
setDefaultAnimationVars(); setDefaultAnimationVars();
@@ -631,6 +646,10 @@ void CConfigManager::setDefaultAnimationVars() {
INITANIMCFG("windowsOut"); INITANIMCFG("windowsOut");
INITANIMCFG("windowsMove"); INITANIMCFG("windowsMove");
// layers
INITANIMCFG("layersIn");
INITANIMCFG("layersOut");
// fade // fade
INITANIMCFG("fadeIn"); INITANIMCFG("fadeIn");
INITANIMCFG("fadeOut"); INITANIMCFG("fadeOut");
@@ -654,6 +673,9 @@ void CConfigManager::setDefaultAnimationVars() {
CREATEANIMCFG("borderangle", "global"); CREATEANIMCFG("borderangle", "global");
CREATEANIMCFG("workspaces", "global"); CREATEANIMCFG("workspaces", "global");
CREATEANIMCFG("layersIn", "layers");
CREATEANIMCFG("layersOut", "layers");
CREATEANIMCFG("windowsIn", "windows"); CREATEANIMCFG("windowsIn", "windows");
CREATEANIMCFG("windowsOut", "windows"); CREATEANIMCFG("windowsOut", "windows");
CREATEANIMCFG("windowsMove", "windows"); CREATEANIMCFG("windowsMove", "windows");
@@ -664,6 +686,8 @@ void CConfigManager::setDefaultAnimationVars() {
CREATEANIMCFG("fadeShadow", "fade"); CREATEANIMCFG("fadeShadow", "fade");
CREATEANIMCFG("fadeDim", "fade"); CREATEANIMCFG("fadeDim", "fade");
CREATEANIMCFG("fadeLayers", "fade"); CREATEANIMCFG("fadeLayers", "fade");
CREATEANIMCFG("fadeLayersIn", "fadeLayers");
CREATEANIMCFG("fadeLayersOut", "fadeLayers");
CREATEANIMCFG("specialWorkspace", "workspaces"); CREATEANIMCFG("specialWorkspace", "workspaces");
} }
@@ -738,6 +762,12 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
g_pHyprOpenGL->m_bReloadScreenShader = true; g_pHyprOpenGL->m_bReloadScreenShader = true;
// parseError will be displayed next frame // parseError will be displayed next frame
if (result.error)
m_szConfigErrors = result.getError();
else
m_szConfigErrors = "";
if (result.error && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:suppress_errors"))) if (result.error && !std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("debug:suppress_errors")))
g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0));
else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1) else if (std::any_cast<Hyprlang::INT>(m_pConfig->getConfigValue("autogenerated")) == 1)
@@ -761,12 +791,11 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
refreshGroupBarGradients(); refreshGroupBarGradients();
// Updates dynamic window and workspace rules // Updates dynamic window and workspace rules
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWorkspaces) {
if (!w->m_bIsMapped) if (w->inert())
continue; continue;
g_pCompositor->updateWorkspaceWindows(w->m_iID);
w->updateDynamicRules(); g_pCompositor->updateWorkspaceSpecialRenderData(w->m_iID);
w->updateSpecialRenderData();
} }
// Update window border colors // Update window border colors
@@ -935,17 +964,43 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) {
return SMonitorRule{.name = "", .resolution = Vector2D(0, 0), .offset = Vector2D(-INT32_MAX, -INT32_MAX), .scale = -1}; // 0, 0 is preferred and -1, -1 is auto return SMonitorRule{.name = "", .resolution = Vector2D(0, 0), .offset = Vector2D(-INT32_MAX, -INT32_MAX), .scale = -1}; // 0, 0 is preferred and -1, -1 is auto
} }
SWorkspaceRule CConfigManager::getWorkspaceRuleFor(CWorkspace* pWorkspace) { SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) {
const auto WORKSPACEIDSTR = std::to_string(pWorkspace->m_iID); SWorkspaceRule mergedRule{};
const auto IT = std::find_if(m_dWorkspaceRules.begin(), m_dWorkspaceRules.end(), [&](const auto& other) { for (auto& rule : m_dWorkspaceRules) {
return other.workspaceName == pWorkspace->m_szName /* name matches */ if (!pWorkspace->matchesStaticSelector(rule.workspaceString))
|| (pWorkspace->m_bIsSpecialWorkspace && other.workspaceName.starts_with("special:") && continue;
other.workspaceName.substr(8) == pWorkspace->m_szName) /* special and special:name */
|| (pWorkspace->m_iID > 0 && WORKSPACEIDSTR == other.workspaceName); /* id matches and workspace is numerical */ if (rule.isDefault)
}); mergedRule.isDefault = true;
if (IT == m_dWorkspaceRules.end()) if (rule.isPersistent)
return SWorkspaceRule{}; mergedRule.isPersistent = true;
return *IT; if (rule.gapsIn.has_value())
mergedRule.gapsIn = rule.gapsIn;
if (rule.gapsOut.has_value())
mergedRule.gapsOut = rule.gapsOut;
if (rule.borderSize.has_value())
mergedRule.borderSize = rule.borderSize;
if (rule.border.has_value())
mergedRule.border = rule.border;
if (rule.rounding.has_value())
mergedRule.rounding = rule.rounding;
if (rule.decorate.has_value())
mergedRule.decorate = rule.decorate;
if (rule.shadow.has_value())
mergedRule.shadow = rule.shadow;
if (rule.onCreatedEmptyRunCmd.has_value())
mergedRule.onCreatedEmptyRunCmd = rule.onCreatedEmptyRunCmd;
if (rule.defaultName.has_value())
mergedRule.defaultName = rule.defaultName;
if (!rule.layoutopts.empty()) {
for (const auto& layoutopt : rule.layoutopts) {
mergedRule.layoutopts[layoutopt.first] = layoutopt.second;
}
}
}
return mergedRule;
} }
std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow, bool dynamic, bool shadowExec) { std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow, bool dynamic, bool shadowExec) {
@@ -1038,13 +1093,14 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow, bool
continue; continue;
} }
if (rule.iOnWorkspace != -1) { if (!rule.szOnWorkspace.empty()) {
if (rule.iOnWorkspace != g_pCompositor->getWindowsOnWorkspace(pWindow->m_iWorkspaceID)) const auto PWORKSPACE = pWindow->m_pWorkspace;
if (!PWORKSPACE || !PWORKSPACE->matchesStaticSelector(rule.szOnWorkspace))
continue; continue;
} }
if (!rule.szWorkspace.empty()) { if (!rule.szWorkspace.empty()) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = pWindow->m_pWorkspace;
if (!PWORKSPACE) if (!PWORKSPACE)
continue; continue;
@@ -1269,7 +1325,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
/* fullscreen */ /* fullscreen */
m->vrrActive = true; m->vrrActive = true;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m->activeWorkspace); const auto PWORKSPACE = m->activeWorkspace;
if (!PWORKSPACE) if (!PWORKSPACE)
return; // ??? return; // ???
@@ -1326,10 +1382,9 @@ std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname
for (auto& wr : m_dWorkspaceRules) { for (auto& wr : m_dWorkspaceRules) {
const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName; const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName;
if (WSNAME == wsname) { if (WSNAME == wsname)
return wr.monitor; return wr.monitor;
} }
}
return ""; return "";
} }
@@ -1893,7 +1948,8 @@ bool windowRuleValid(const std::string& RULE) {
} }
bool layerRuleValid(const std::string& RULE) { bool layerRuleValid(const std::string& RULE) {
return RULE == "noanim" || RULE == "blur" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE.starts_with("xray") || RULE.starts_with("animation"); return RULE == "noanim" || RULE == "blur" || RULE == "blurpopups" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE == "dimaround" ||
RULE.starts_with("xray") || RULE.starts_with("animation");
} }
std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) { std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
@@ -2027,7 +2083,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
result = removeBeginEndSpacesTabs(result); result = removeBeginEndSpacesTabs(result);
if (result.back() == ',') if (!result.empty() && result.back() == ',')
result.pop_back(); result.pop_back();
return result; return result;
@@ -2064,7 +2120,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0; rule.bFocus = extract(FOCUSPOS + 6) == "1" ? 1 : 0;
if (ONWORKSPACEPOS != std::string::npos) if (ONWORKSPACEPOS != std::string::npos)
rule.iOnWorkspace = configStringToInt(extract(ONWORKSPACEPOS + 12)); rule.szOnWorkspace = extract(ONWORKSPACEPOS + 12);
if (RULE == "unset") { if (RULE == "unset") {
std::erase_if(m_dWindowRules, [&](const SWindowRule& other) { std::erase_if(m_dWindowRules, [&](const SWindowRule& other) {
@@ -2101,7 +2157,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
if (rule.bFocus != -1 && rule.bFocus != other.bFocus) if (rule.bFocus != -1 && rule.bFocus != other.bFocus)
return false; return false;
if (rule.iOnWorkspace != -1 && rule.iOnWorkspace != other.iOnWorkspace) if (!rule.szOnWorkspace.empty() && rule.szOnWorkspace != other.szOnWorkspace)
return false; return false;
return true; return true;
@@ -2164,24 +2220,24 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
auto rules = value.substr(FIRST_DELIM + 1); auto rules = value.substr(FIRST_DELIM + 1);
SWorkspaceRule wsRule; SWorkspaceRule wsRule;
wsRule.workspaceString = first_ident; wsRule.workspaceString = first_ident;
if (id == WORKSPACE_INVALID) { // if (id == WORKSPACE_INVALID) {
// it could be the monitor. If so, second value MUST be // // it could be the monitor. If so, second value MUST be
// the workspace. // // the workspace.
const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1); // const auto WORKSPACE_DELIM = value.find_first_of(',', FIRST_DELIM + 1);
auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1))); // auto wsIdent = removeBeginEndSpacesTabs(value.substr(FIRST_DELIM + 1, (WORKSPACE_DELIM - FIRST_DELIM - 1)));
id = getWorkspaceIDFromString(wsIdent, name); // id = getWorkspaceIDFromString(wsIdent, name);
if (id == WORKSPACE_INVALID) { // if (id == WORKSPACE_INVALID) {
Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent); // Debug::log(ERR, "Invalid workspace identifier found: {}", wsIdent);
return "Invalid workspace identifier found: " + wsIdent; // return "Invalid workspace identifier found: " + wsIdent;
} // }
wsRule.monitor = first_ident; // wsRule.monitor = first_ident;
wsRule.workspaceString = wsIdent; // wsRule.workspaceString = wsIdent;
wsRule.isDefault = true; // backwards compat // wsRule.isDefault = true; // backwards compat
rules = value.substr(WORKSPACE_DELIM + 1); // rules = value.substr(WORKSPACE_DELIM + 1);
} // }
const static std::string ruleOnCreatedEmtpy = "on-created-empty:"; const static std::string ruleOnCreatedEmpty = "on-created-empty:";
const static int ruleOnCreatedEmtpyLen = ruleOnCreatedEmtpy.length(); const static int ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length();
auto assignRule = [&](std::string rule) -> std::optional<std::string> { auto assignRule = [&](std::string rule) -> std::optional<std::string> {
size_t delim = std::string::npos; size_t delim = std::string::npos;
@@ -2217,8 +2273,8 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
wsRule.isPersistent = configStringToInt(rule.substr(delim + 11)); wsRule.isPersistent = configStringToInt(rule.substr(delim + 11));
else if ((delim = rule.find("defaultName:")) != std::string::npos) else if ((delim = rule.find("defaultName:")) != std::string::npos)
wsRule.defaultName = rule.substr(delim + 12); wsRule.defaultName = rule.substr(delim + 12);
else if ((delim = rule.find(ruleOnCreatedEmtpy)) != std::string::npos) else if ((delim = rule.find(ruleOnCreatedEmpty)) != std::string::npos)
wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmtpyLen)); wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmptyLen));
else if ((delim = rule.find("layoutopt:")) != std::string::npos) { else if ((delim = rule.find("layoutopt:")) != std::string::npos) {
std::string opt = rule.substr(delim + 10); std::string opt = rule.substr(delim + 10);
if (!opt.contains(":")) { if (!opt.contains(":")) {

View File

@@ -13,10 +13,10 @@
#include <optional> #include <optional>
#include <functional> #include <functional>
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include "../Window.hpp"
#include "../helpers/WLClasses.hpp" #include "../helpers/WLClasses.hpp"
#include "../helpers/Monitor.hpp" #include "../helpers/Monitor.hpp"
#include "../helpers/VarList.hpp" #include "../helpers/VarList.hpp"
#include "../desktop/Window.hpp"
#include "defaultConfig.hpp" #include "defaultConfig.hpp"
#include "ConfigDataValues.hpp" #include "ConfigDataValues.hpp"
@@ -28,6 +28,8 @@
#define HANDLE void* #define HANDLE void*
class CWindow;
struct SWorkspaceRule { struct SWorkspaceRule {
std::string monitor = ""; std::string monitor = "";
std::string workspaceString = ""; std::string workspaceString = "";
@@ -104,7 +106,7 @@ class CConfigManager {
static std::string getMainConfigPath(); static std::string getMainConfigPath();
SMonitorRule getMonitorRuleFor(const CMonitor&); SMonitorRule getMonitorRuleFor(const CMonitor&);
SWorkspaceRule getWorkspaceRuleFor(CWorkspace*); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace);
std::string getDefaultWorkspaceFor(const std::string&); std::string getDefaultWorkspaceFor(const std::string&);
CMonitor* getBoundMonitorForWS(const std::string&); CMonitor* getBoundMonitorForWS(const std::string&);
@@ -141,6 +143,7 @@ class CConfigManager {
void addExecRule(const SExecRequestedRule&); void addExecRule(const SExecRequestedRule&);
void handlePluginLoads(); void handlePluginLoads();
std::string getErrors();
// keywords // keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&); std::optional<std::string> handleRawExec(const std::string&, const std::string&);
@@ -192,6 +195,7 @@ class CConfigManager {
std::deque<std::string> firstExecRequests; std::deque<std::string> firstExecRequests;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_szConfigErrors = "";
// internal methods // internal methods
void setAnimForChildren(SAnimationPropertyConfig* const); void setAnimForChildren(SAnimationPropertyConfig* const);

View File

@@ -5,6 +5,7 @@
#include <hyprlang.hpp> #include <hyprlang.hpp>
#include "../debug/Log.hpp" #include "../debug/Log.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "ConfigManager.hpp"
template <typename T> template <typename T>
class CConfigValue { class CConfigValue {

View File

@@ -15,23 +15,16 @@
#include <string> #include <string>
#include <typeindex> #include <typeindex>
#include "../config/ConfigDataValues.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../managers/CursorManager.hpp" #include "../managers/CursorManager.hpp"
#include "../hyprerror/HyprError.hpp"
static void trimTrailingComma(std::string& str) { static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',') if (!str.empty() && str.back() == ',')
str.pop_back(); str.pop_back();
} }
static std::string getWorkspaceNameFromSpecialID(const int workspaceID) {
if (workspaceID == 0)
return "";
const auto* workspace = g_pCompositor->getWorkspaceByID(workspaceID);
if (!workspace)
return "";
return workspace->m_szName;
}
static std::string formatToString(uint32_t drmFormat) { static std::string formatToString(uint32_t drmFormat) {
switch (drmFormat) { switch (drmFormat) {
case DRM_FORMAT_XRGB2101010: return "XRGB2101010"; case DRM_FORMAT_XRGB2101010: return "XRGB2101010";
@@ -110,16 +103,17 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
"dpmsStatus": {}, "dpmsStatus": {},
"vrr": {}, "vrr": {},
"activelyTearing": {}, "activelyTearing": {},
"disabled": {},
"currentFormat": "{}", "currentFormat": "{}",
"availableModes": [{}] "availableModes": [{}]
}},)#", }},)#",
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""),
(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, (m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
m->activeWorkspace, (m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(),
escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"), (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"),
m->tearingState.activelyTearing ? "true" : "false", formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
} }
trimTrailingComma(result); trimTrailingComma(result);
@@ -130,18 +124,17 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
if (!m->output || m->ID == -1ull) if (!m->output || m->ID == -1ull)
continue; continue;
result += result += std::format(
std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial " "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
"workspace: {} ({})\n\treserved: {} " "workspace: {} ({})\n\treserved: {} "
"{} {} {}\n\tscale: {:.2f}\n\ttransform: " "{} {} {}\n\tscale: {:.2f}\n\ttransform: "
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", "{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspace, (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(),
(m->activeWorkspace == -1 ? "" : g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName), m->specialWorkspaceID, (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""),
getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED),
(int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing, formatToString(m->drmFormat), m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
availableModesForOutput(m.get(), format));
} }
} }
@@ -210,30 +203,23 @@ static std::string getWindowData(CWindow* w, eHyprCtlOutputFormat format) {
"focusHistoryID": {} "focusHistoryID": {}
}},)#", }},)#",
(uintptr_t)w, (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (uintptr_t)w, (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_iWorkspaceID, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" : escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (int64_t)w->m_iMonitorID,
g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w)), escapeJSONStrings(g_pXWaylandManager->getTitle(w)), escapeJSONStrings(w->m_szInitialClass),
std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
((int)w->m_bIsFloating == 1 ? "true" : "false"), (int64_t)w->m_iMonitorID, escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w)), (w->m_bIsFullscreen ? "true" : "false"), (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0),
escapeJSONStrings(g_pXWaylandManager->getTitle(w)), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(),
((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? (int)g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), (uintptr_t)w->m_pSwallowed, getFocusHistoryID(w)); w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), (uintptr_t)w->m_pSwallowed, getFocusHistoryID(w));
} else { } else {
return std::format( return std::format("Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
"Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: "
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\txwayland: {}\n\tpinned: " "{}\n\txwayland: {}\n\tpinned: "
"{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", "{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n",
(uintptr_t)w, w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (int)w->m_vRealSize.goal().x, (uintptr_t)w, w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y,
(int)w->m_vRealSize.goal().y, w->m_iWorkspaceID, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID,
(w->m_iWorkspaceID == -1 ? "" : (!w->m_pWorkspace ? "" : std::to_string(w->workspaceID())), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w),
g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName : g_pXWaylandManager->getTitle(w), w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))), (w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bFakeFullscreenState, getGroupedData(w, format),
(int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w), g_pXWaylandManager->getTitle(w), w->m_szInitialClass, w->m_szInitialTitle, (uintptr_t)w->m_pSwallowed, getFocusHistoryID(w));
w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
(int)w->m_bFakeFullscreenState, getGroupedData(w, format), (uintptr_t)w->m_pSwallowed, getFocusHistoryID(w));
} }
} }
@@ -263,7 +249,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
return result; return result;
} }
static std::string getWorkspaceData(CWorkspace* w, eHyprCtlOutputFormat format) { static std::string getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) {
const auto PLASTW = w->getLastFocusedWindow(); const auto PLASTW = w->getLastFocusedWindow();
const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID);
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
@@ -338,9 +324,9 @@ std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string requ
return "unsafe state"; return "unsafe state";
std::string result = ""; std::string result = "";
auto w = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); auto w = g_pCompositor->m_pLastMonitor->activeWorkspace;
if (!w) if (!valid(w))
return "internal error"; return "internal error";
return getWorkspaceData(w, format); return getWorkspaceData(w, format);
@@ -352,7 +338,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request)
if (format == eHyprCtlOutputFormat::FORMAT_JSON) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "["; result += "[";
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getWorkspaceData(w.get(), format); result += getWorkspaceData(w, format);
result += ","; result += ",";
} }
@@ -360,7 +346,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request)
result += "]"; result += "]";
} else { } else {
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
result += getWorkspaceData(w.get(), format); result += getWorkspaceData(w, format);
} }
} }
@@ -497,6 +483,29 @@ std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
return result; return result;
} }
std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = "";
std::string currErrors = g_pConfigManager->getErrors();
CVarList errLines(currErrors, 0, '\n');
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto line : errLines) {
result += std::format(
R"#(
"{}",)#",
escapeJSONStrings(line));
}
trimTrailingComma(result);
result += "\n]\n";
} else {
for (auto line : errLines) {
result += std::format("{}\n", line);
}
}
return result;
}
std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
std::string result = ""; std::string result = "";
@@ -633,7 +642,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
} }
for (auto& d : g_pInputManager->m_lTablets) { for (auto& d : g_pInputManager->m_lTablets) {
result += std::format("\tTablet at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.name); result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)&d, d.name, d.wlrTablet->width_mm, d.wlrTablet->height_mm);
} }
for (auto& d : g_pInputManager->m_lTabletTools) { for (auto& d : g_pInputManager->m_lTabletTools) {
@@ -803,7 +812,7 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg +
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + "\n\nflags: (if any)\n"; ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + "\n\nflags: (if any)\n";
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "legacyrenderer\n"; result += "legacyrenderer\n";
@@ -825,8 +834,9 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
"commit_message": "{}", "commit_message": "{}",
"commit_date": "{}", "commit_date": "{}",
"tag": "{}", "tag": "{}",
"commits": {},
"flags": [)#", "flags": [)#",
GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG); GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS);
#ifdef LEGACY_RENDERER #ifdef LEGACY_RENDERER
result += "\"legacyrenderer\","; result += "\"legacyrenderer\",";
@@ -1201,10 +1211,27 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
PWINDOW->m_sSpecialRenderData.alphaInactiveOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sSpecialRenderData.alphaInactiveOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alphainactive") { } else if (PROP == "alphainactive") {
PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock); PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock);
} else if (PROP == "activebordercolor") { } else if (PROP == "alphafullscreenoverride") {
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock); PWINDOW->m_sSpecialRenderData.alphaFullscreenOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "inactivebordercolor") { } else if (PROP == "alphafullscreen") {
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock); PWINDOW->m_sSpecialRenderData.alphaFullscreen.forceSetIgnoreLocked(std::stof(VAL), lock);
} else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") {
CGradientValueData colorData = {};
if (vars.size() > 4) {
for (int i = 3; i < static_cast<int>(lock ? vars.size() - 1 : vars.size()); ++i) {
const auto TOKEN = vars[i];
if (TOKEN.ends_with("deg"))
colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0);
else
colorData.m_vColors.push_back(configStringToInt(TOKEN));
}
} else if (VAL != "-1")
colorData.m_vColors.push_back(configStringToInt(VAL));
if (PROP == "activebordercolor")
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(colorData, lock);
else
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(colorData, lock);
} else if (PROP == "forcergbx") { } else if (PROP == "forcergbx") {
PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock); PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "bordersize") { } else if (PROP == "bordersize") {
@@ -1427,6 +1454,9 @@ std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
} else if (OPERATION == "list") { } else if (OPERATION == "list") {
const auto PLUGINS = g_pPluginSystem->getAllPlugins(); const auto PLUGINS = g_pPluginSystem->getAllPlugins();
if (PLUGINS.size() == 0)
return "no plugins loaded";
std::string list = ""; std::string list = "";
for (auto& p : PLUGINS) { for (auto& p : PLUGINS) {
list += std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description); list += std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description);
@@ -1531,6 +1561,7 @@ CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"animations", true, animationsRequest}); registerCommand(SHyprCtlCommand{"animations", true, animationsRequest});
registerCommand(SHyprCtlCommand{"rollinglog", true, rollinglogRequest}); registerCommand(SHyprCtlCommand{"rollinglog", true, rollinglogRequest});
registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest}); registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest});
registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});

View File

@@ -76,7 +76,7 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
const auto SCALE = pMonitor->scale; const auto SCALE = pMonitor->scale;
const auto MONSIZE = pMonitor->vecPixelSize; const auto MONSIZE = pMonitor->vecTransformedSize;
cairo_text_extents_t cairoExtents; cairo_text_extents_t cairoExtents;
int iconW = 0, iconH = 0; int iconW = 0, iconH = 0;
@@ -185,16 +185,19 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
void CHyprNotificationOverlay::draw(CMonitor* pMonitor) { void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
if (m_pLastMonitor != pMonitor || !m_pCairo || !m_pCairoSurface) { const auto MONSIZE = pMonitor->vecTransformedSize;
if (m_pLastMonitor != pMonitor || m_vecLastSize != MONSIZE || !m_pCairo || !m_pCairoSurface) {
if (m_pCairo && m_pCairoSurface) { if (m_pCairo && m_pCairoSurface) {
cairo_destroy(m_pCairo); cairo_destroy(m_pCairo);
cairo_surface_destroy(m_pCairoSurface); cairo_surface_destroy(m_pCairoSurface);
} }
m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, MONSIZE.x, MONSIZE.y);
m_pCairo = cairo_create(m_pCairoSurface); m_pCairo = cairo_create(m_pCairoSurface);
m_pLastMonitor = pMonitor; m_pLastMonitor = pMonitor;
m_vecLastSize = MONSIZE;
} }
// Draw the notifications // Draw the notifications
@@ -232,9 +235,9 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
#endif #endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
CBox pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y}; CBox pMonBox = {0, 0, MONSIZE.x, MONSIZE.y};
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f); g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
} }

View File

@@ -55,6 +55,7 @@ class CHyprNotificationOverlay {
cairo_t* m_pCairo = nullptr; cairo_t* m_pCairo = nullptr;
CMonitor* m_pLastMonitor = nullptr; CMonitor* m_pLastMonitor = nullptr;
Vector2D m_vecLastSize = Vector2D(-1, -1);
CTexture m_tTexture; CTexture m_tTexture;

View File

@@ -1,8 +1,12 @@
#include "Constraint.hpp" #include "Constraint.hpp"
#include "WLSurface.hpp" #include "WLSurface.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
CConstraint::CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner) : m_pOwner(owner), m_pConstraint(constraint) { CConstraint::CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner) : m_pOwner(owner), m_pConstraint(constraint) {
RASSERT(!constraint->data, "CConstraint: attempted to duplicate ownership");
constraint->data = this;
initSignals(); initSignals();
m_vCursorPosOnActivate = g_pInputManager->getMouseCoordsInternal(); m_vCursorPosOnActivate = g_pInputManager->getMouseCoordsInternal();
@@ -33,8 +37,11 @@ void CConstraint::initSignals() {
} }
void CConstraint::onDestroy() { void CConstraint::onDestroy() {
if (active()) hyprListener_setConstraintRegion.removeCallback();
deactivate(); hyprListener_destroyConstraint.removeCallback();
if (active() && isLocked())
g_pCompositor->warpCursorTo(logicPositionHint(), true);
// this is us // this is us
m_pOwner->m_pConstraint.reset(); m_pOwner->m_pConstraint.reset();
@@ -56,8 +63,18 @@ void CConstraint::onCommit() {
const auto COMMITTED = m_pConstraint->current.committed; const auto COMMITTED = m_pConstraint->current.committed;
if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) { if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) {
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
m_bHintSet = true; m_bHintSet = true;
m_vPositionHint = {m_pConstraint->current.cursor_hint.x, m_pConstraint->current.cursor_hint.y};
float scale = 1.f;
const auto PWINDOW = m_pOwner->getWindow();
if (PWINDOW) {
const auto ISXWL = PWINDOW->m_bIsX11;
scale = ISXWL && *PXWLFORCESCALEZERO ? PWINDOW->m_fX11SurfaceScaledBy : 1.f;
}
m_vPositionHint = {m_pConstraint->current.cursor_hint.x / scale, m_pConstraint->current.cursor_hint.y / scale};
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
} }
@@ -92,7 +109,6 @@ void CConstraint::deactivate() {
if (!m_bActive) if (!m_bActive)
return; return;
wlr_pointer_constraint_v1_send_deactivated(m_pConstraint);
m_bActive = false; m_bActive = false;
if (isLocked()) if (isLocked())
@@ -100,12 +116,16 @@ void CConstraint::deactivate() {
if (m_pConstraint->lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT) if (m_pConstraint->lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT)
m_bDead = true; m_bDead = true;
wlr_pointer_constraint_v1_send_deactivated(m_pConstraint);
} }
void CConstraint::activate() { void CConstraint::activate() {
if (m_bActive || m_bDead) if (m_bActive || m_bDead)
return; return;
m_bActive = true;
// TODO: hack, probably not a super duper great idea // TODO: hack, probably not a super duper great idea
if (g_pCompositor->m_sSeat.seat->pointer_state.focused_surface != m_pOwner->wlr()) { if (g_pCompositor->m_sSeat.seat->pointer_state.focused_surface != m_pOwner->wlr()) {
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal(); const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
@@ -115,7 +135,6 @@ void CConstraint::activate() {
g_pCompositor->warpCursorTo(logicPositionHint(), true); g_pCompositor->warpCursorTo(logicPositionHint(), true);
wlr_pointer_constraint_v1_send_activated(m_pConstraint); wlr_pointer_constraint_v1_send_activated(m_pConstraint);
m_bActive = true;
} }
bool CConstraint::active() { bool CConstraint::active() {

View File

@@ -0,0 +1,6 @@
#pragma once
#include <memory>
class CWorkspace;
typedef std::shared_ptr<CWorkspace> PHLWORKSPACE;

View File

@@ -1,4 +1,5 @@
#include "Popup.hpp" #include "Popup.hpp"
#include "../config/ConfigValue.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
CPopup::CPopup(CWindow* pOwner) : m_pWindowOwner(pOwner) { CPopup::CPopup(CWindow* pOwner) : m_pWindowOwner(pOwner) {
@@ -117,6 +118,9 @@ void CPopup::onMap() {
unconstrain(); unconstrain();
sendScale(); sendScale();
if (m_pLayerOwner && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
} }
void CPopup::onUnmap() { void CPopup::onUnmap() {
@@ -131,6 +135,9 @@ void CPopup::onUnmap() {
m_pSubsurfaceHead.reset(); m_pSubsurfaceHead.reset();
g_pInputManager->simulateMouseMovement(); g_pInputManager->simulateMouseMovement();
if (m_pLayerOwner && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
} }
void CPopup::onCommit(bool ignoreSiblings) { void CPopup::onCommit(bool ignoreSiblings) {
@@ -139,6 +146,18 @@ void CPopup::onCommit(bool ignoreSiblings) {
return; return;
} }
if (m_pWindowOwner && (!m_pWindowOwner->m_bIsMapped || !m_pWindowOwner->m_pWorkspace->m_bVisible)) {
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from a subsurface of {} because it's invisible.", m_pWindowOwner);
return;
}
if (!m_pWLR->base->surface->mapped)
return;
const auto COORDS = coordsGlobal(); const auto COORDS = coordsGlobal();
const auto COORDSLOCAL = coordsRelativeToParent(); const auto COORDSLOCAL = coordsRelativeToParent();
@@ -152,12 +171,15 @@ void CPopup::onCommit(bool ignoreSiblings) {
m_vLastPos = COORDSLOCAL; m_vLastPos = COORDSLOCAL;
} }
if (!ignoreSiblings) if (!ignoreSiblings && m_pSubsurfaceHead)
m_pSubsurfaceHead->recheckDamageForSubsurfaces(); m_pSubsurfaceHead->recheckDamageForSubsurfaces();
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y); g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
m_bRequestedReposition = false; m_bRequestedReposition = false;
if (m_pLayerOwner && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP)
g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer));
} }
void CPopup::onReposition() { void CPopup::onReposition() {

View File

@@ -7,38 +7,24 @@ static void onNewSubsurface(void* owner, void* data);
CSubsurface::CSubsurface(CWindow* pOwner) : m_pWindowParent(pOwner) { CSubsurface::CSubsurface(CWindow* pOwner) : m_pWindowParent(pOwner) {
initSignals(); initSignals();
initExistingSubsurfaces(pOwner->m_pWLSurface.wlr());
wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &pOwner->m_pWLSurface.wlr()->current.subsurfaces_below, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
wl_list_for_each(wlrSubsurface, &pOwner->m_pWLSurface.wlr()->current.subsurfaces_above, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
} }
CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) { CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) {
initSignals(); initSignals();
initExistingSubsurfaces(pOwner->m_sWLSurface.wlr());
wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &pOwner->m_sWLSurface.wlr()->current.subsurfaces_below, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
wl_list_for_each(wlrSubsurface, &pOwner->m_sWLSurface.wlr()->current.subsurfaces_above, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
} }
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) { CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) {
m_sWLSurface.assign(pSubsurface->surface, this); m_sWLSurface.assign(pSubsurface->surface, this);
initSignals(); initSignals();
initExistingSubsurfaces(); initExistingSubsurfaces(pSubsurface->surface);
} }
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) { CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
m_sWLSurface.assign(pSubsurface->surface, this); m_sWLSurface.assign(pSubsurface->surface, this);
initSignals(); initSignals();
initExistingSubsurfaces(); initExistingSubsurfaces(pSubsurface->surface);
} }
CSubsurface::~CSubsurface() { CSubsurface::~CSubsurface() {
@@ -47,6 +33,8 @@ CSubsurface::~CSubsurface() {
if (!m_pSubsurface) if (!m_pSubsurface)
return; return;
m_pSubsurface->data = nullptr;
hyprListener_commitSubsurface.removeCallback(); hyprListener_commitSubsurface.removeCallback();
hyprListener_destroySubsurface.removeCallback(); hyprListener_destroySubsurface.removeCallback();
} }
@@ -78,6 +66,7 @@ static void onUnmapSubsurface(void* owner, void* data) {
void CSubsurface::initSignals() { void CSubsurface::initSignals() {
if (m_pSubsurface) { if (m_pSubsurface) {
m_pSubsurface->data = this;
hyprListener_commitSubsurface.initCallback(&m_pSubsurface->surface->events.commit, &onCommitSubsurface, this, "CSubsurface"); hyprListener_commitSubsurface.initCallback(&m_pSubsurface->surface->events.commit, &onCommitSubsurface, this, "CSubsurface");
hyprListener_destroySubsurface.initCallback(&m_pSubsurface->events.destroy, &onDestroySubsurface, this, "CSubsurface"); hyprListener_destroySubsurface.initCallback(&m_pSubsurface->events.destroy, &onDestroySubsurface, this, "CSubsurface");
hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface"); hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface");
@@ -117,7 +106,7 @@ void CSubsurface::recheckDamageForSubsurfaces() {
void CSubsurface::onCommit() { void CSubsurface::onCommit() {
// no damaging if it's not visible // no damaging if it's not visible
if (m_pWindowParent && !g_pHyprRenderer->shouldRenderWindow(m_pWindowParent)) { if (m_pWindowParent && (!m_pWindowParent->m_bIsMapped || !m_pWindowParent->m_pWorkspace->m_bVisible)) {
m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage"); static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
@@ -225,15 +214,12 @@ Vector2D CSubsurface::coordsGlobal() {
return coords; return coords;
} }
void CSubsurface::initExistingSubsurfaces() { void CSubsurface::initExistingSubsurfaces(wlr_surface* pSurface) {
if (m_pWindowParent)
return;
wlr_subsurface* wlrSubsurface; wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_below, current.link) { wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_below, current.link) {
::onNewSubsurface(this, wlrSubsurface); ::onNewSubsurface(this, wlrSubsurface);
} }
wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_above, current.link) { wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_above, current.link) {
::onNewSubsurface(this, wlrSubsurface); ::onNewSubsurface(this, wlrSubsurface);
} }
} }

View File

@@ -54,6 +54,6 @@ class CSubsurface {
bool m_bInert = false; bool m_bInert = false;
void initSignals(); void initSignals();
void initExistingSubsurfaces(); void initExistingSubsurfaces(wlr_surface* pSurface);
void checkSiblingDamage(); void checkSiblingDamage();
}; };

View File

@@ -1,19 +1,20 @@
#include "Window.hpp" #include "Window.hpp"
#include "Compositor.hpp" #include "../Compositor.hpp"
#include "render/decorations/CHyprDropShadowDecoration.hpp" #include "../render/decorations/CHyprDropShadowDecoration.hpp"
#include "render/decorations/CHyprGroupBarDecoration.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "render/decorations/CHyprBorderDecoration.hpp" #include "../render/decorations/CHyprBorderDecoration.hpp"
#include "config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include <any>
CWindow::CWindow() { CWindow::CWindow() {
m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE); m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), this, AVARDAMAGE_ENTIRE);
m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE); m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), this, AVARDAMAGE_ENTIRE);
m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER); m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), this, AVARDAMAGE_BORDER);
m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), (void*)this, AVARDAMAGE_BORDER); m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), this, AVARDAMAGE_BORDER);
m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE); m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), this, AVARDAMAGE_ENTIRE);
m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE); m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), this, AVARDAMAGE_ENTIRE);
m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW); m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), this, AVARDAMAGE_SHADOW);
m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE); m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), this, AVARDAMAGE_ENTIRE);
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this)); addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
addWindowDeco(std::make_unique<CHyprBorderDecoration>(this)); addWindowDeco(std::make_unique<CHyprBorderDecoration>(this));
@@ -377,43 +378,43 @@ void CWindow::updateSurfaceScaleTransformDetails() {
this); this);
} }
void CWindow::moveToWorkspace(int workspaceID) { void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
if (m_iWorkspaceID == workspaceID) if (m_pWorkspace == pWorkspace)
return; return;
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty"); static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
const int OLDWORKSPACE = m_iWorkspaceID; const auto OLDWORKSPACE = m_pWorkspace;
m_iWorkspaceID = workspaceID; m_pWorkspace = pWorkspace;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); setAnimationsToMove();
updateSpecialRenderData(); g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID);
g_pCompositor->updateWorkspaceSpecialRenderData(OLDWORKSPACE->m_iID);
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (PWORKSPACE) { if (valid(pWorkspace)) {
g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", std::format("{:x},{}", (uintptr_t)this, PWORKSPACE->m_szName)}); g_pEventManager->postEvent(SHyprIPCEvent{"movewindow", std::format("{:x},{}", (uintptr_t)this, pWorkspace->m_szName)});
g_pEventManager->postEvent(SHyprIPCEvent{"movewindowv2", std::format("{:x},{},{}", (uintptr_t)this, PWORKSPACE->m_iID, PWORKSPACE->m_szName)}); g_pEventManager->postEvent(SHyprIPCEvent{"movewindowv2", std::format("{:x},{},{}", (uintptr_t)this, pWorkspace->m_iID, pWorkspace->m_szName)});
EMIT_HOOK_EVENT("moveWindow", (std::vector<void*>{this, PWORKSPACE})); EMIT_HOOK_EVENT("moveWindow", (std::vector<std::any>{this, pWorkspace}));
} }
if (m_pSwallowed) { if (m_pSwallowed) {
m_pSwallowed->moveToWorkspace(workspaceID); m_pSwallowed->moveToWorkspace(pWorkspace);
m_pSwallowed->m_iMonitorID = m_iMonitorID; m_pSwallowed->m_iMonitorID = m_iMonitorID;
} }
// update xwayland coords // update xwayland coords
g_pXWaylandManager->setWindowSize(this, m_vRealSize.value()); g_pXWaylandManager->setWindowSize(this, m_vRealSize.value());
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) { if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE->m_iID) == 0 && *PCLOSEONLASTSPECIAL) {
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE); if (const auto PMONITOR = g_pCompositor->getMonitorFromID(OLDWORKSPACE->m_iMonitorID); PMONITOR)
if (PWS) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWS->m_iMonitorID); PMONITOR)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
} }
}
CWindow* CWindow::X11TransientFor() { CWindow* CWindow::X11TransientFor() {
if (!m_bIsX11) if (!m_bIsX11)
@@ -452,6 +453,10 @@ void CWindow::onUnmap() {
if (g_pCompositor->m_pLastWindow == this) if (g_pCompositor->m_pLastWindow == this)
g_pCompositor->m_pLastWindow = nullptr; g_pCompositor->m_pLastWindow = nullptr;
if (g_pInputManager->currentlyDraggedWindow == this)
g_pInputManager->currentlyDraggedWindow = nullptr;
m_iLastWorkspace = m_pWorkspace->m_iID;
m_vRealPosition.setCallbackOnEnd(unregisterVar); m_vRealPosition.setCallbackOnEnd(unregisterVar);
m_vRealSize.setCallbackOnEnd(unregisterVar); m_vRealSize.setCallbackOnEnd(unregisterVar);
@@ -466,13 +471,11 @@ void CWindow::onUnmap() {
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other == this; }); std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other == this; });
m_pWLSurface.unassign();
hyprListener_unmapWindow.removeCallback(); hyprListener_unmapWindow.removeCallback();
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(m_iWorkspaceID) == 0 && g_pCompositor->isWorkspaceSpecial(m_iWorkspaceID)) { if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID) if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace)
PMONITOR->setSpecialWorkspace(nullptr); PMONITOR->setSpecialWorkspace(nullptr);
} }
@@ -481,7 +484,11 @@ void CWindow::onUnmap() {
if (PMONITOR && PMONITOR->solitaryClient == this) if (PMONITOR && PMONITOR->solitaryClient == this)
PMONITOR->solitaryClient = nullptr; PMONITOR->solitaryClient = nullptr;
g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID); g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
m_pWorkspace.reset();
if (m_bIsX11) if (m_bIsX11)
return; return;
@@ -491,9 +498,6 @@ void CWindow::onUnmap() {
} }
void CWindow::onMap() { void CWindow::onMap() {
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this), this);
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped) // JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
m_vRealPosition.resetAllCallbacks(); m_vRealPosition.resetAllCallbacks();
m_vRealSize.resetAllCallbacks(); m_vRealSize.resetAllCallbacks();
@@ -524,6 +528,7 @@ void CWindow::onMap() {
"CWindow"); "CWindow");
m_vReportedSize = m_vPendingReportedSize; m_vReportedSize = m_vPendingReportedSize;
m_bAnimatingIn = true;
for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) { for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) {
if (ctrl->pWlrHint->surface != m_pWLSurface.wlr()) if (ctrl->pWlrHint->surface != m_pWLSurface.wlr())
@@ -607,25 +612,36 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
continue; continue;
if (r == "override") { if (r == "override") {
if (opacityIDX == 1) { if (opacityIDX == 1)
m_sSpecialRenderData.alphaOverride = true; m_sSpecialRenderData.alphaOverride = true;
else if (opacityIDX == 2)
m_sSpecialRenderData.alphaInactiveOverride = true; m_sSpecialRenderData.alphaInactiveOverride = true;
} else if (opacityIDX == 2) else if (opacityIDX == 3)
m_sSpecialRenderData.alphaInactiveOverride = true; m_sSpecialRenderData.alphaFullscreenOverride = true;
} else { } else {
if (opacityIDX == 0) { if (opacityIDX == 0) {
m_sSpecialRenderData.alpha = std::stof(r); m_sSpecialRenderData.alpha = std::stof(r);
m_sSpecialRenderData.alphaInactive = std::stof(r); m_sSpecialRenderData.alphaOverride = false;
} else if (opacityIDX == 1) { } else if (opacityIDX == 1) {
m_sSpecialRenderData.alphaInactive = std::stof(r); m_sSpecialRenderData.alphaInactive = std::stof(r);
m_sSpecialRenderData.alphaInactiveOverride = false; m_sSpecialRenderData.alphaInactiveOverride = false;
} else if (opacityIDX == 2) {
m_sSpecialRenderData.alphaFullscreen = std::stof(r);
m_sSpecialRenderData.alphaFullscreenOverride = false;
} else { } else {
throw std::runtime_error("more than 2 alpha values"); throw std::runtime_error("more than 3 alpha values");
} }
opacityIDX++; opacityIDX++;
} }
} }
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;
}
} catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule == "noanim") { } else if (r.szRule == "noanim") {
m_sAdditionalConfigData.forceNoAnims = true; m_sAdditionalConfigData.forceNoAnims = true;
@@ -838,6 +854,8 @@ void CWindow::createGroup() {
addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(this)); addWindowDeco(std::make_unique<CHyprGroupBarDecoration>(this));
g_pLayoutManager->getCurrentLayout()->recalculateWindow(this); g_pLayoutManager->getCurrentLayout()->recalculateWindow(this);
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pCompositor->updateAllWindowsAnimatedDecorationValues();
} }
} }
@@ -849,7 +867,11 @@ void CWindow::destroyGroup() {
return; return;
} }
m_sGroupData.pNextWindow = nullptr; m_sGroupData.pNextWindow = nullptr;
m_sGroupData.head = false;
updateWindowDecos(); updateWindowDecos();
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
return; return;
} }
@@ -876,6 +898,10 @@ void CWindow::destroyGroup() {
w->updateWindowDecos(); w->updateWindowDecos();
} }
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
g_pCompositor->updateWorkspaceWindows(workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
} }
CWindow* CWindow::getGroupHead() { CWindow* CWindow::getGroupHead() {
@@ -945,7 +971,7 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
const auto PCURRENT = getGroupCurrent(); const auto PCURRENT = getGroupCurrent();
const bool FULLSCREEN = PCURRENT->m_bIsFullscreen; const bool FULLSCREEN = PCURRENT->m_bIsFullscreen;
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PCURRENT->m_iWorkspaceID); const auto WORKSPACE = PCURRENT->m_pWorkspace;
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
@@ -1038,9 +1064,11 @@ void CWindow::updateGroupOutputs() {
CWindow* curr = m_sGroupData.pNextWindow; CWindow* curr = m_sGroupData.pNextWindow;
const auto WS = m_pWorkspace;
while (curr != this) { while (curr != this) {
curr->m_iMonitorID = m_iMonitorID; curr->m_iMonitorID = m_iMonitorID;
curr->moveToWorkspace(m_iWorkspaceID); curr->moveToWorkspace(WS);
curr->m_vRealPosition = m_vRealPosition.goal(); curr->m_vRealPosition = m_vRealPosition.goal();
curr->m_vRealSize = m_vRealSize.goal(); curr->m_vRealSize = m_vRealSize.goal();
@@ -1057,7 +1085,10 @@ bool CWindow::opaque() {
if (m_fAlpha.value() != 1.f || m_fActiveInactiveAlpha.value() != 1.f) if (m_fAlpha.value() != 1.f || m_fActiveInactiveAlpha.value() != 1.f)
return false; return false;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); if (m_vRealSize.goal().floor() != m_vReportedSize)
return false;
const auto PWORKSPACE = m_pWorkspace;
if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall) if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall)
return false; return false;
@@ -1087,20 +1118,23 @@ float CWindow::rounding() {
} }
void CWindow::updateSpecialRenderData() { void CWindow::updateSpecialRenderData() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID); const auto PWORKSPACE = m_pWorkspace;
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
bool border = true; updateSpecialRenderData(WORKSPACERULE);
}
void CWindow::updateSpecialRenderData(const SWorkspaceRule& workspaceRule) {
static auto PNOBORDERONFLOATING = CConfigValue<Hyprlang::INT>("general:no_border_on_floating"); static auto PNOBORDERONFLOATING = CConfigValue<Hyprlang::INT>("general:no_border_on_floating");
bool border = true;
if (m_bIsFloating && *PNOBORDERONFLOATING == 1) if (m_bIsFloating && *PNOBORDERONFLOATING == 1)
border = false; border = false;
m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(border); m_sSpecialRenderData.border = workspaceRule.border.value_or(border);
m_sSpecialRenderData.borderSize = WORKSPACERULE.borderSize.value_or(-1); m_sSpecialRenderData.borderSize = workspaceRule.borderSize.value_or(-1);
m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true); m_sSpecialRenderData.decorate = workspaceRule.decorate.value_or(true);
m_sSpecialRenderData.rounding = WORKSPACERULE.rounding.value_or(true); m_sSpecialRenderData.rounding = workspaceRule.rounding.value_or(true);
m_sSpecialRenderData.shadow = WORKSPACERULE.shadow.value_or(true); m_sSpecialRenderData.shadow = workspaceRule.shadow.value_or(true);
} }
int CWindow::getRealBorderSize() { int CWindow::getRealBorderSize() {
@@ -1123,7 +1157,7 @@ bool CWindow::canBeTorn() {
} }
bool CWindow::shouldSendFullscreenState() { bool CWindow::shouldSendFullscreenState() {
const auto MODE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID)->m_efFullscreenMode; const auto MODE = m_pWorkspace->m_efFullscreenMode;
return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL))); return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL)));
} }
@@ -1143,3 +1177,66 @@ bool CWindow::visibleOnMonitor(CMonitor* pMonitor) {
return wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, wbox.pWlr()); return wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, wbox.pWlr());
} }
void CWindow::setAnimationsToMove() {
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
m_vRealPosition.setConfig(PANIMCFG);
m_vRealSize.setConfig(PANIMCFG);
m_bAnimatingIn = false;
}
void CWindow::onWorkspaceAnimUpdate() {
// clip box for animated offsets
if (!m_bIsFloating || m_bPinned || m_bIsFullscreen) {
m_vFloatingOffset = Vector2D(0, 0);
return;
}
Vector2D offset;
const auto PWORKSPACE = m_pWorkspace;
if (!PWORKSPACE)
return;
const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
if (!PWSMON)
return;
const auto WINBB = getFullWindowBoundingBox();
if (PWORKSPACE->m_vRenderOffset.value().x != 0) {
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().x / PWSMON->vecSize.x;
if (WINBB.x < PWSMON->vecPosition.x)
offset.x += (PWSMON->vecPosition.x - WINBB.x) * PROGRESS;
if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x)
offset.x += (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS;
} else if (PWORKSPACE->m_vRenderOffset.value().y != 0) {
const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().y / PWSMON->vecSize.y;
if (WINBB.y < PWSMON->vecPosition.y)
offset.y += (PWSMON->vecPosition.y - WINBB.y) * PROGRESS;
if (WINBB.y + WINBB.height > PWSMON->vecPosition.y + PWSMON->vecSize.y)
offset.y += (WINBB.y + WINBB.height - PWSMON->vecPosition.y - PWSMON->vecSize.y) * PROGRESS;
}
m_vFloatingOffset = offset;
}
int CWindow::popupsCount() {
if (m_bIsX11)
return 1;
int no = 0;
wlr_xdg_surface_for_each_popup_surface(
m_uSurface.xdg, [](wlr_surface* s, int x, int y, void* data) { *(int*)data += 1; }, &no);
return no;
}
int CWindow::workspaceID() {
return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace;
}
bool CWindow::onSpecialWorkspace() {
return m_pWorkspace ? m_pWorkspace->m_bIsSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_iLastWorkspace);
}

View File

@@ -1,16 +1,17 @@
#pragma once #pragma once
#include "defines.hpp" #include "../defines.hpp"
#include "desktop/Subsurface.hpp" #include "Subsurface.hpp"
#include "helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include "render/decorations/IHyprWindowDecoration.hpp" #include "../render/decorations/IHyprWindowDecoration.hpp"
#include <deque> #include <deque>
#include "config/ConfigDataValues.hpp" #include "../config/ConfigDataValues.hpp"
#include "helpers/Vector2D.hpp" #include "../helpers/Vector2D.hpp"
#include "desktop/WLSurface.hpp" #include "WLSurface.hpp"
#include "desktop/Popup.hpp" #include "Popup.hpp"
#include "macros.hpp" #include "../macros.hpp"
#include "managers/XWaylandManager.hpp" #include "../managers/XWaylandManager.hpp"
#include "DesktopTypes.hpp"
enum eIdleInhibitMode { enum eIdleInhibitMode {
IDLEINHIBIT_NONE = 0, IDLEINHIBIT_NONE = 0,
@@ -129,6 +130,8 @@ struct SWindowSpecialRenderData {
CWindowOverridableVar<float> alpha = 1.f; CWindowOverridableVar<float> alpha = 1.f;
CWindowOverridableVar<bool> alphaInactiveOverride = false; CWindowOverridableVar<bool> alphaInactiveOverride = false;
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
CWindowOverridableVar<bool> alphaFullscreenOverride = false;
CWindowOverridableVar<float> alphaFullscreen = -1.f; // -1 means unset
CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset
CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset
@@ -180,7 +183,7 @@ struct SWindowRule {
int bFullscreen = -1; int bFullscreen = -1;
int bPinned = -1; int bPinned = -1;
int bFocus = -1; int bFocus = -1;
int iOnWorkspace = -1; std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any std::string szWorkspace = ""; // empty means any
}; };
@@ -237,6 +240,9 @@ class CWindow {
Vector2D m_vLastFloatingSize; Vector2D m_vLastFloatingSize;
Vector2D m_vLastFloatingPosition; Vector2D m_vLastFloatingPosition;
// for floating window offset in workspace animations
Vector2D m_vFloatingOffset = Vector2D(0, 0);
// this is used for pseudotiling // this is used for pseudotiling
bool m_bIsPseudotiled = false; bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(0, 0); Vector2D m_vPseudoSize = Vector2D(0, 0);
@@ -251,7 +257,7 @@ class CWindow {
std::string m_szTitle = ""; std::string m_szTitle = "";
std::string m_szInitialTitle = ""; std::string m_szInitialTitle = "";
std::string m_szInitialClass = ""; std::string m_szInitialClass = "";
int m_iWorkspaceID = -1; PHLWORKSPACE m_pWorkspace;
bool m_bIsMapped = false; bool m_bIsMapped = false;
@@ -296,6 +302,7 @@ class CWindow {
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
Vector2D m_vOriginalClosedSize; // drawing the closing animations Vector2D m_vOriginalClosedSize; // drawing the closing animations
SWindowDecorationExtents m_eOriginalClosedExtents; SWindowDecorationExtents m_eOriginalClosedExtents;
bool m_bAnimatingIn = false;
// For pinned (sticky) windows // For pinned (sticky) windows
bool m_bPinned = false; bool m_bPinned = false;
@@ -380,7 +387,7 @@ class CWindow {
void destroyToplevelHandle(); void destroyToplevelHandle();
void updateToplevel(); void updateToplevel();
void updateSurfaceScaleTransformDetails(); void updateSurfaceScaleTransformDetails();
void moveToWorkspace(int); void moveToWorkspace(PHLWORKSPACE);
CWindow* X11TransientFor(); CWindow* X11TransientFor();
void onUnmap(); void onUnmap();
void onMap(); void onMap();
@@ -396,13 +403,17 @@ class CWindow {
bool shouldSendFullscreenState(); bool shouldSendFullscreenState();
void setSuspended(bool suspend); void setSuspended(bool suspend);
bool visibleOnMonitor(CMonitor* pMonitor); bool visibleOnMonitor(CMonitor* pMonitor);
int workspaceID();
bool onSpecialWorkspace();
int getRealBorderSize(); int getRealBorderSize();
void updateSpecialRenderData(); void updateSpecialRenderData();
void updateSpecialRenderData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(void* ptr); void onBorderAngleAnimEnd(void* ptr);
bool isInCurvedCorner(double x, double y); bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos); bool hasPopupAt(const Vector2D& pos);
int popupsCount();
void applyGroupRules(); void applyGroupRules();
void createGroup(); void createGroup();
@@ -418,11 +429,14 @@ class CWindow {
void insertWindowToGroup(CWindow* pWindow); void insertWindowToGroup(CWindow* pWindow);
void updateGroupOutputs(); void updateGroupOutputs();
void switchWithWindowInGroup(CWindow* pWindow); void switchWithWindowInGroup(CWindow* pWindow);
void setAnimationsToMove();
void onWorkspaceAnimUpdate();
private: private:
// For hidden windows and stuff // For hidden windows and stuff
bool m_bHidden = false; bool m_bHidden = false;
bool m_bSuspended = false; bool m_bSuspended = false;
int m_iLastWorkspace = WORKSPACE_INVALID;
}; };
/** /**
@@ -457,7 +471,7 @@ struct std::formatter<CWindow*, CharT> : std::formatter<CharT> {
std::format_to(out, "["); std::format_to(out, "[");
std::format_to(out, "Window {:x}: title: \"{}\"", (uintptr_t)w, w->m_szTitle); std::format_to(out, "Window {:x}: title: \"{}\"", (uintptr_t)w, w->m_szTitle);
if (formatWorkspace) if (formatWorkspace)
std::format_to(out, ", workspace: {}", w->m_iWorkspaceID); std::format_to(out, ", workspace: {}", w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID);
if (formatMonitor) if (formatMonitor)
std::format_to(out, ", monitor: {}", w->m_iMonitorID); std::format_to(out, ", monitor: {}", w->m_iMonitorID);
if (formatClass) if (formatClass)

View File

@@ -2,34 +2,51 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special) { PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); PHLWORKSPACE workspace = std::make_shared<CWorkspace>(id, monitorID, name, special);
workspace->init(workspace);
if (!PMONITOR) { return workspace;
Debug::log(ERR, "Attempted a creation of CWorkspace with an invalid monitor?");
return;
} }
CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special) {
m_iMonitorID = monitorID; m_iMonitorID = monitorID;
m_iID = id; m_iID = id;
m_szName = name; m_szName = name;
m_bIsSpecialWorkspace = special; m_bIsSpecialWorkspace = special;
}
m_vRenderOffset.m_pWorkspace = this; void CWorkspace::init(PHLWORKSPACE self) {
m_vRenderOffset.create(special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), nullptr, m_pSelf = self;
m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"),
self, AVARDAMAGE_ENTIRE);
m_fAlpha.create(AVARTYPE_FLOAT,
m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), self,
AVARDAMAGE_ENTIRE); AVARDAMAGE_ENTIRE);
m_fAlpha.m_pWorkspace = this;
m_fAlpha.create(AVARTYPE_FLOAT, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"),
nullptr, AVARDAMAGE_ENTIRE);
m_fAlpha.setValueAndWarp(1.f); m_fAlpha.setValueAndWarp(1.f);
m_vRenderOffset.registerVar(); m_vRenderOffset.registerVar();
m_fAlpha.registerVar(); m_fAlpha.registerVar();
const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(this); const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self);
if (RULEFORTHIS.defaultName.has_value()) if (RULEFORTHIS.defaultName.has_value())
m_szName = RULEFORTHIS.defaultName.value(); m_szName = RULEFORTHIS.defaultName.value();
m_pFocusedWindowHook = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any param) {
const auto PWINDOW = std::any_cast<CWindow*>(param);
if (PWINDOW == m_pLastFocusedWindow)
m_pLastFocusedWindow = nullptr;
});
m_bInert = false;
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self);
m_bPersistent = WORKSPACERULE.isPersistent;
if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd)
g_pKeybindManager->spawn(*cmd);
g_pEventManager->postEvent({"createworkspace", m_szName}); g_pEventManager->postEvent({"createworkspace", m_szName});
g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)}); g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)});
EMIT_HOOK_EVENT("createWorkspace", this); EMIT_HOOK_EVENT("createWorkspace", this);
@@ -40,15 +57,31 @@ CWorkspace::~CWorkspace() {
Debug::log(LOG, "Destroying workspace ID {}", m_iID); Debug::log(LOG, "Destroying workspace ID {}", m_iID);
// check if g_pHookSystem and g_pEventManager exist, they might be destroyed as in when the compositor is closing.
if (g_pHookSystem)
g_pHookSystem->unhook(m_pFocusedWindowHook);
if (g_pEventManager) {
g_pEventManager->postEvent({"destroyworkspace", m_szName}); g_pEventManager->postEvent({"destroyworkspace", m_szName});
g_pEventManager->postEvent({"destroyworkspacev2", std::format("{},{}", m_iID, m_szName)}); g_pEventManager->postEvent({"destroyworkspacev2", std::format("{},{}", m_iID, m_szName)});
EMIT_HOOK_EVENT("destroyWorkspace", this); EMIT_HOOK_EVENT("destroyWorkspace", this);
} }
}
void CWorkspace::startAnim(bool in, bool left, bool instant) { void CWorkspace::startAnim(bool in, bool left, bool instant) {
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle; const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); 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) {
if (!g_pCompositor->windowValidMapped(w.get()) || w->workspaceID() != m_iID)
continue;
w->onWorkspaceAnimUpdate();
};
});
if (ANIMSTYLE.starts_with("slidefade")) { if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
float movePerc = 100.f; float movePerc = 100.f;
@@ -150,13 +183,13 @@ void CWorkspace::moveToMonitor(const int& id) {
} }
CWindow* CWorkspace::getLastFocusedWindow() { CWindow* CWorkspace::getLastFocusedWindow() {
if (!g_pCompositor->windowValidMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow->m_iWorkspaceID != m_iID) if (!g_pCompositor->windowValidMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow->workspaceID() != m_iID)
return nullptr; return nullptr;
return m_pLastFocusedWindow; return m_pLastFocusedWindow;
} }
void CWorkspace::rememberPrevWorkspace(const CWorkspace* prev) { void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) {
if (!prev) { if (!prev) {
m_sPrevWorkspace.iID = -1; m_sPrevWorkspace.iID = -1;
m_sPrevWorkspace.name = ""; m_sPrevWorkspace.name = "";
@@ -182,3 +215,242 @@ std::string CWorkspace::getConfigName() {
return "name:" + m_szName; return "name:" + m_szName;
} }
bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
auto selector = removeBeginEndSpacesTabs(selector_);
if (selector.empty())
return true;
if (isNumber(selector)) {
std::string wsname = "";
int wsid = getWorkspaceIDFromString(selector, wsname);
if (wsid == WORKSPACE_INVALID)
return false;
return wsid == m_iID;
} else if (selector.starts_with("name:")) {
return m_szName == selector.substr(5);
} else if (selector.starts_with("special")) {
return m_szName == selector;
} else {
// parse selector
for (size_t i = 0; i < selector.length(); ++i) {
const char& cur = selector[i];
if (std::isspace(cur))
continue;
// Allowed selectors:
// r - range: r[1-5]
// s - special: s[true]
// n - named: n[true] or n[s:string] or n[e:string]
// m - monitor: m[monitor_selector]
// w - windowCount: w[1-4] or w[1], optional flag t or f for tiled or floating and
// flag g to count groups instead of windows, e.g. w[t1-2], w[fg4]
const auto NEXTSPACE = selector.find_first_of(' ', i);
std::string prop = selector.substr(i, NEXTSPACE == std::string::npos ? std::string::npos : NEXTSPACE - i);
i = std::min(NEXTSPACE, std::string::npos - 1);
if (cur == 'r') {
int from = 0, to = 0;
if (!prop.starts_with("r[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
if (!prop.contains("-")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
const auto DASHPOS = prop.find("-");
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
try {
from = std::stoll(LHS);
to = std::stoll(RHS);
} catch (std::exception& e) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
if (to < from || to < 1 || from < 1) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
if (std::clamp(m_iID, from, to) != m_iID)
return false;
continue;
}
if (cur == 's') {
if (!prop.starts_with("s[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
const auto SHOULDBESPECIAL = configStringToInt(prop);
if ((bool)SHOULDBESPECIAL != m_bIsSpecialWorkspace)
return false;
continue;
}
if (cur == 'm') {
if (!prop.starts_with("m[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
const auto PMONITOR = g_pCompositor->getMonitorFromString(prop);
if (!(PMONITOR ? PMONITOR->ID == m_iMonitorID : false))
return false;
continue;
}
if (cur == 'n') {
if (!prop.starts_with("n[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
if (prop.starts_with("s:") && !m_szName.starts_with(prop.substr(2)))
return false;
if (prop.starts_with("e:") && !m_szName.ends_with(prop.substr(2)))
return false;
const auto WANTSNAMED = configStringToInt(prop);
if (WANTSNAMED != (m_iID <= -1337))
return false;
continue;
}
if (cur == 'w') {
int from = 0, to = 0;
if (!prop.starts_with("w[") || !prop.ends_with("]")) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
prop = prop.substr(2, prop.length() - 3);
int wantsOnlyTiled = -1;
bool wantsCountGroup = false;
int flagCount = 0;
for (auto& flag : prop) {
if (flag == 't' && wantsOnlyTiled == -1) {
wantsOnlyTiled = 1;
flagCount++;
} else if (flag == 'f' && wantsOnlyTiled == -1) {
wantsOnlyTiled = 0;
flagCount++;
} else if (flag == 'g' && !wantsCountGroup) {
wantsCountGroup = true;
flagCount++;
} else {
break;
}
}
prop = prop.substr(flagCount);
if (!prop.contains("-")) {
// try single
if (!isNumber(prop)) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
try {
from = std::stoll(prop);
} catch (std::exception& e) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
int count;
if (wantsCountGroup)
count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled));
else
count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled));
if (count != from)
return false;
continue;
}
const auto DASHPOS = prop.find("-");
const auto LHS = prop.substr(0, DASHPOS), RHS = prop.substr(DASHPOS + 1);
if (!isNumber(LHS) || !isNumber(RHS)) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
try {
from = std::stoll(LHS);
to = std::stoll(RHS);
} catch (std::exception& e) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
if (to < from || to < 1 || from < 1) {
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
int count;
if (wantsCountGroup)
count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled));
else
count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled));
if (std::clamp(count, from, to) != count)
return false;
continue;
}
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
return true;
}
UNREACHABLE();
return false;
}
void CWorkspace::markInert() {
m_bInert = true;
m_iID = WORKSPACE_INVALID;
m_iMonitorID = -1;
m_bVisible = false;
}
bool CWorkspace::inert() {
return m_bInert;
}

View File

@@ -3,6 +3,7 @@
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include <string> #include <string>
#include "../defines.hpp" #include "../defines.hpp"
#include "DesktopTypes.hpp"
enum eFullscreenMode : int8_t { enum eFullscreenMode : int8_t {
FULLSCREEN_INVALID = -1, FULLSCREEN_INVALID = -1,
@@ -14,6 +15,8 @@ class CWindow;
class CWorkspace { class CWorkspace {
public: public:
static PHLWORKSPACE create(int id, int monitorID, std::string name, bool special = false);
// use create() don't use this
CWorkspace(int id, int monitorID, std::string name, bool special = false); CWorkspace(int id, int monitorID, std::string name, bool special = false);
~CWorkspace(); ~CWorkspace();
@@ -39,6 +42,9 @@ class CWorkspace {
CAnimatedVariable<float> m_fAlpha; CAnimatedVariable<float> m_fAlpha;
bool m_bForceRendering = false; bool m_bForceRendering = false;
// allows damage to propagate.
bool m_bVisible = false;
// "scratchpad" // "scratchpad"
bool m_bIsSpecialWorkspace = false; bool m_bIsSpecialWorkspace = false;
@@ -52,8 +58,10 @@ class CWorkspace {
// last monitor (used on reconnect) // last monitor (used on reconnect)
std::string m_szLastMonitor = ""; std::string m_szLastMonitor = "";
// Whether the user configured command for on-created-empty has been executed, if any bool m_bPersistent = false;
bool m_bOnCreatedEmptyExecuted = false;
// Inert: destroyed and invalid. If this is true, release the ptr you have.
bool inert();
void startAnim(bool in, bool left, bool instant = false); void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on); void setActive(bool on);
@@ -61,7 +69,25 @@ class CWorkspace {
void moveToMonitor(const int&); void moveToMonitor(const int&);
CWindow* getLastFocusedWindow(); CWindow* getLastFocusedWindow();
void rememberPrevWorkspace(const CWorkspace* prevWorkspace); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace);
std::string getConfigName(); std::string getConfigName();
bool matchesStaticSelector(const std::string& selector);
void markInert();
private:
void init(PHLWORKSPACE self);
HOOK_CALLBACK_FN* m_pFocusedWindowHook = nullptr;
bool m_bInert = true;
std::weak_ptr<CWorkspace> m_pSelf;
}; };
inline bool valid(const PHLWORKSPACE& ref) {
if (!ref)
return false;
return !ref->inert();
}

View File

@@ -126,12 +126,6 @@ namespace Events {
LISTENER(newTextInput); LISTENER(newTextInput);
LISTENER(newVirtualKeyboard); LISTENER(newVirtualKeyboard);
// IME Popups
DYNLISTENFUNC(mapInputPopup);
DYNLISTENFUNC(unmapInputPopup);
DYNLISTENFUNC(commitInputPopup);
DYNLISTENFUNC(destroyInputPopup);
// Touch // Touch
LISTENER(touchBegin); LISTENER(touchBegin);
LISTENER(touchEnd); LISTENER(touchEnd);

View File

@@ -148,6 +148,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
(!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained()); (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained());
if (GRABSFOCUS) { if (GRABSFOCUS) {
g_pInputManager->releaseAllMouseButtons();
g_pCompositor->focusSurface(layersurface->layerSurface->surface); g_pCompositor->focusSurface(layersurface->layerSurface->surface);
const auto LOCAL = const auto LOCAL =
@@ -162,7 +163,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, CBox geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width,
layersurface->geometry.height}; layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto WORKSPACE = PMONITOR->activeWorkspace;
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
layersurface->startAnimation(!(layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); layersurface->startAnimation(!(layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
@@ -236,7 +237,7 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
&surfaceCoords, &pFoundLayerSurface); &surfaceCoords, &pFoundLayerSurface);
if (!foundSurface && g_pCompositor->m_pLastWindow) { if (!foundSurface && g_pCompositor->m_pLastWindow && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) {
// if there isn't any, focus the last window // if there isn't any, focus the last window
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(nullptr);

View File

@@ -117,6 +117,13 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
} }
void Events::listener_monitorFrame(void* owner, void* data) { void Events::listener_monitorFrame(void* owner, void* data) {
if (g_pCompositor->m_bExitTriggered) {
// Only signal cleanup once
g_pCompositor->m_bExitTriggered = false;
g_pCompositor->cleanup();
return;
}
CMonitor* const PMONITOR = (CMonitor*)owner; CMonitor* const PMONITOR = (CMonitor*)owner;
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {

View File

@@ -35,7 +35,10 @@ void setAnimToMove(void* data) {
CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data; CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data;
if (animvar->getWindow() && !animvar->getWindow()->m_vRealPosition.isBeingAnimated() && !animvar->getWindow()->m_vRealSize.isBeingAnimated()) {
animvar->setConfig(PANIMCFG); animvar->setConfig(PANIMCFG);
animvar->getWindow()->m_bAnimatingIn = false;
}
} }
void Events::listener_mapWindow(void* owner, void* data) { void Events::listener_mapWindow(void* owner, void* data) {
@@ -50,9 +53,13 @@ void Events::listener_mapWindow(void* owner, void* data) {
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen"); static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen");
auto PMONITOR = g_pCompositor->m_pLastMonitor; auto PMONITOR = g_pCompositor->m_pLastMonitor;
auto PWORKSPACE = PMONITOR->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); if (!g_pCompositor->m_pLastMonitor) {
g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({}));
PMONITOR = g_pCompositor->m_pLastMonitor;
}
auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_iMonitorID = PMONITOR->ID;
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace; PWINDOW->m_pWorkspace = PWORKSPACE;
PWINDOW->m_bIsMapped = true; PWINDOW->m_bIsMapped = true;
PWINDOW->m_bReadyToDelete = false; PWINDOW->m_bReadyToDelete = false;
PWINDOW->m_bFadingOut = false; PWINDOW->m_bFadingOut = false;
@@ -146,7 +153,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID)); g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID));
PMONITOR = PMONITORFROMID; PMONITOR = PMONITORFROMID;
} }
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace; PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW); Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW);
} catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); } } catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r.szRule, r.szValue, e.what()); }
@@ -280,16 +287,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWORKSPACE = pWorkspace; PWORKSPACE = pWorkspace;
PWINDOW->m_iWorkspaceID = pWorkspace->m_iID; PWINDOW->m_pWorkspace = pWorkspace;
PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID; PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID;
if (g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->specialWorkspaceID && !pWorkspace->m_bIsSpecialWorkspace) if (g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeSpecialWorkspace && !pWorkspace->m_bIsSpecialWorkspace)
workspaceSilent = true; workspaceSilent = true;
if (!workspaceSilent) { if (!workspaceSilent) {
if (pWorkspace->m_bIsSpecialWorkspace) if (pWorkspace->m_bIsSpecialWorkspace)
g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID)->setSpecialWorkspace(pWorkspace); g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID)->setSpecialWorkspace(pWorkspace);
else if (PMONITOR->activeWorkspace != REQUESTEDWORKSPACEID) else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID)
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName); g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
PMONITOR = g_pCompositor->m_pLastMonitor; PMONITOR = g_pCompositor->m_pLastMonitor;
@@ -625,7 +632,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// fix some xwayland apps that don't behave nicely // fix some xwayland apps that don't behave nicely
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID); g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID());
if (PMONITOR && PWINDOW->m_iX11Type == 2) if (PMONITOR && PWINDOW->m_iX11Type == 2)
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
@@ -697,7 +704,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
} }
// remove the fullscreen window status from workspace if we closed it // remove the fullscreen window status from workspace if we closed it
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); const auto PWORKSPACE = PWINDOW->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && PWINDOW->m_bIsFullscreen) if (PWORKSPACE->m_bHasFullscreenWindow && PWINDOW->m_bIsFullscreen)
PWORKSPACE->m_bHasFullscreenWindow = false; PWORKSPACE->m_bHasFullscreenWindow = false;
@@ -716,7 +723,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE) if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
g_pCompositor->focusWindow(PWINDOWCANDIDATE); g_pCompositor->focusWindow(PWINDOWCANDIDATE);
if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->m_iWorkspaceID) == 0) if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0)
g_pInputManager->refocus(); g_pInputManager->refocus();
g_pInputManager->sendMotionEventsToFocused(); g_pInputManager->sendMotionEventsToFocused();
@@ -751,7 +758,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pInputManager->recheckIdleInhibitorStatus(); g_pInputManager->recheckIdleInhibitorStatus();
// force report all sizes (QT sometimes has an issue with this) // force report all sizes (QT sometimes has an issue with this)
g_pCompositor->forceReportSizesToWindowsOnWorkspace(PWINDOW->m_iWorkspaceID); g_pCompositor->forceReportSizesToWindowsOnWorkspace(PWINDOW->workspaceID());
// update lastwindow after focus // update lastwindow after focus
PWINDOW->onUnmap(); PWINDOW->onUnmap();
@@ -775,22 +782,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->initial_commit) { if (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->initial_commit) {
Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow(); Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow(PWINDOW);
if (g_pXWaylandManager->shouldBeFloated(PWINDOW, true))
predSize = {};
Vector2D maxSize = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->pending.max_width, PWINDOW->m_uSurface.xdg->toplevel->pending.max_height};
if ((maxSize.x > 0 && maxSize.x < predSize.x) || (maxSize.y > 0 && maxSize.y < predSize.y))
predSize = {};
for (auto& r : g_pConfigManager->getMatchingRules(PWINDOW, true, true)) {
if (r.szRule.starts_with("float")) {
predSize = {};
break;
}
}
Debug::log(LOG, "Layout predicts size {} for {}", predSize, PWINDOW); Debug::log(LOG, "Layout predicts size {} for {}", predSize, PWINDOW);
@@ -808,6 +800,35 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_pPendingSizeAck.reset(); PWINDOW->m_pPendingSizeAck.reset();
} }
if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) {
const auto MINSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.min_width, PWINDOW->m_uSurface.xdg->toplevel->current.min_height};
const auto MAXSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.max_width, PWINDOW->m_uSurface.xdg->toplevel->current.max_height};
if (MAXSIZE > Vector2D{1, 1}) {
const auto REALSIZE = PWINDOW->m_vRealSize.goal();
Vector2D newSize = REALSIZE;
if (MAXSIZE.x < newSize.x)
newSize.x = MAXSIZE.x;
if (MAXSIZE.y < newSize.y)
newSize.y = MAXSIZE.y;
if (MINSIZE.x > newSize.x)
newSize.x = MINSIZE.x;
if (MINSIZE.y > newSize.y)
newSize.y = MINSIZE.y;
const Vector2D DELTA = REALSIZE - newSize;
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0;
PWINDOW->m_vRealSize = newSize;
g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true);
g_pHyprRenderer->damageWindow(PWINDOW);
}
}
if (!PWINDOW->m_pWorkspace->m_bVisible)
return;
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
@@ -831,34 +852,6 @@ void Events::listener_commitWindow(void* owner, void* data) {
} }
} }
} }
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
return;
const auto MINSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.min_width, PWINDOW->m_uSurface.xdg->toplevel->current.min_height};
const auto MAXSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.max_width, PWINDOW->m_uSurface.xdg->toplevel->current.max_height};
if (MAXSIZE < Vector2D{1, 1})
return;
const auto REALSIZE = PWINDOW->m_vRealSize.goal();
Vector2D newSize = REALSIZE;
if (MAXSIZE.x < newSize.x)
newSize.x = MAXSIZE.x;
if (MAXSIZE.y < newSize.y)
newSize.y = MAXSIZE.y;
if (MINSIZE.x > newSize.x)
newSize.x = MINSIZE.x;
if (MINSIZE.y > newSize.y)
newSize.y = MINSIZE.y;
const Vector2D DELTA = REALSIZE - newSize;
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0;
PWINDOW->m_vRealSize = newSize;
g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true);
g_pHyprRenderer->damageWindow(PWINDOW);
} }
void Events::listener_destroyWindow(void* owner, void* data) { void Events::listener_destroyWindow(void* owner, void* data) {
@@ -874,6 +867,8 @@ void Events::listener_destroyWindow(void* owner, void* data) {
g_pCompositor->m_pLastFocus = nullptr; g_pCompositor->m_pLastFocus = nullptr;
} }
PWINDOW->m_pWLSurface.unassign();
PWINDOW->hyprListener_commitWindow.removeCallback(); PWINDOW->hyprListener_commitWindow.removeCallback();
PWINDOW->hyprListener_mapWindow.removeCallback(); PWINDOW->hyprListener_mapWindow.removeCallback();
PWINDOW->hyprListener_unmapWindow.removeCallback(); PWINDOW->hyprListener_unmapWindow.removeCallback();
@@ -940,7 +935,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested; const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested;
if (REQUESTED->fullscreen && PWINDOW->m_bIsFullscreen) { if (REQUESTED->fullscreen && PWINDOW->m_bIsFullscreen) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); const auto PWORKSPACE = PWINDOW->m_pWorkspace;
if (PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) { if (PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) {
// Store that we were maximized // Store that we were maximized
PWINDOW->m_bWasMaximized = true; PWINDOW->m_bWasMaximized = true;
@@ -1100,10 +1095,10 @@ void Events::listener_configureX11(void* owner, void* data) {
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_iWorkspaceID)) if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_pWorkspace))
return; // further things are only for visible windows return; // further things are only for visible windows
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace; PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(PWINDOW, true); g_pCompositor->changeWindowZOrder(PWINDOW, true);
@@ -1161,7 +1156,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal(); PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal();
PWINDOW->m_vSize = PWINDOW->m_vRealSize.goal(); PWINDOW->m_vSize = PWINDOW->m_vRealSize.goal();
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace; PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(PWINDOW, true); g_pCompositor->changeWindowZOrder(PWINDOW, true);
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
@@ -1185,11 +1180,15 @@ void Events::listener_associateX11(void* owner, void* data) {
PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW, "XWayland Window"); PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW, "XWayland Window");
PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XWayland Window"); PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.commit, &Events::listener_commitWindow, PWINDOW, "XWayland Window");
PWINDOW->m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(PWINDOW), PWINDOW);
} }
void Events::listener_dissociateX11(void* owner, void* data) { void Events::listener_dissociateX11(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner; const auto PWINDOW = (CWindow*)owner;
PWINDOW->m_pWLSurface.unassign();
PWINDOW->hyprListener_mapWindow.removeCallback(); PWINDOW->hyprListener_mapWindow.removeCallback();
PWINDOW->hyprListener_commitWindow.removeCallback(); PWINDOW->hyprListener_commitWindow.removeCallback();
} }
@@ -1229,6 +1228,8 @@ void Events::listener_newXDGToplevel(wl_listener* listener, void* data) {
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->surface->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window"); PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->surface->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window");
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XDGSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XDG Window"); PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XDGSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XDG Window");
PNEWWINDOW->hyprListener_commitWindow.initCallback(&XDGSURFACE->surface->events.commit, &Events::listener_commitWindow, PNEWWINDOW, "XDG Window"); PNEWWINDOW->hyprListener_commitWindow.initCallback(&XDGSURFACE->surface->events.commit, &Events::listener_commitWindow, PNEWWINDOW, "XDG Window");
PNEWWINDOW->m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(PNEWWINDOW), PNEWWINDOW);
} }
void Events::listener_NewXDGDeco(wl_listener* listener, void* data) { void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {

View File

@@ -6,7 +6,7 @@ CBaseAnimatedVariable::CBaseAnimatedVariable(ANIMATEDVARTYPE type) : m_Type(type
; // dummy var ; // dummy var
} }
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) { void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, CWindow* pWindow, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy; m_eDamagePolicy = policy;
m_pConfig = pAnimConfig; m_pConfig = pAnimConfig;
m_pWindow = pWindow; m_pWindow = pWindow;
@@ -14,6 +14,29 @@ void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, void*
m_bDummy = false; m_bDummy = false;
} }
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, SLayerSurface* pLayer, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pLayer = pLayer;
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pWorkspace = pWorkspace;
m_bDummy = false;
}
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_bDummy = false;
}
CBaseAnimatedVariable::~CBaseAnimatedVariable() { CBaseAnimatedVariable::~CBaseAnimatedVariable() {
unregister(); unregister();
} }

View File

@@ -8,6 +8,7 @@
#include "Color.hpp" #include "Color.hpp"
#include "../macros.hpp" #include "../macros.hpp"
#include "../debug/Log.hpp" #include "../debug/Log.hpp"
#include "../desktop/DesktopTypes.hpp"
enum ANIMATEDVARTYPE { enum ANIMATEDVARTYPE {
AVARTYPE_INVALID = -1, AVARTYPE_INVALID = -1,
@@ -48,10 +49,11 @@ enum AVARDAMAGEPOLICY {
}; };
class CAnimationManager; class CAnimationManager;
class CWorkspace;
struct SLayerSurface; struct SLayerSurface;
struct SAnimationPropertyConfig; struct SAnimationPropertyConfig;
class CHyprRenderer; class CHyprRenderer;
class CWindow;
class CWorkspace;
// Utility to define a concept as a list of possible type // Utility to define a concept as a list of possible type
template <class T, class... U> template <class T, class... U>
@@ -66,7 +68,10 @@ concept Animable = OneOf<T, Vector2D, float, CColor>;
class CBaseAnimatedVariable { class CBaseAnimatedVariable {
public: public:
CBaseAnimatedVariable(ANIMATEDVARTYPE type); CBaseAnimatedVariable(ANIMATEDVARTYPE type);
void create(SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy); void create(SAnimationPropertyConfig* pAnimConfig, CWindow* pWindow, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, SLayerSurface* pLayer, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy);
CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete; CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete; CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
@@ -135,9 +140,13 @@ class CBaseAnimatedVariable {
m_bRemoveEndAfterRan = false; m_bRemoveEndAfterRan = false;
} }
CWindow* getWindow() {
return (CWindow*)m_pWindow;
}
protected: protected:
void* m_pWindow = nullptr; void* m_pWindow = nullptr;
void* m_pWorkspace = nullptr; std::weak_ptr<CWorkspace> m_pWorkspace;
void* m_pLayer = nullptr; void* m_pLayer = nullptr;
SAnimationPropertyConfig* m_pConfig = nullptr; SAnimationPropertyConfig* m_pConfig = nullptr;
@@ -199,11 +208,26 @@ class CAnimatedVariable : public CBaseAnimatedVariable {
public: public:
CAnimatedVariable() : CBaseAnimatedVariable(typeToANIMATEDVARTYPE<VarType>) {} // dummy var CAnimatedVariable() : CBaseAnimatedVariable(typeToANIMATEDVARTYPE<VarType>) {} // dummy var
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) { void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, CWindow* pWindow, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pWindow, policy); create(pAnimConfig, pWindow, policy);
m_Value = value; m_Value = value;
m_Goal = value; m_Goal = value;
} }
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, SLayerSurface* pLayer, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pLayer, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pWorkspace, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, policy);
m_Value = value;
m_Goal = value;
}
using CBaseAnimatedVariable::create; using CBaseAnimatedVariable::create;
@@ -252,14 +276,21 @@ class CAnimatedVariable : public CBaseAnimatedVariable {
// Sets the actual value and goal // Sets the actual value and goal
void setValueAndWarp(const VarType& v) { void setValueAndWarp(const VarType& v) {
m_Goal = v; m_Goal = v;
m_bIsBeingAnimated = true;
warp(); warp();
} }
void warp(bool endCallback = true) override { void warp(bool endCallback = true) override {
if (!m_bIsBeingAnimated)
return;
m_Value = m_Goal; m_Value = m_Goal;
m_bIsBeingAnimated = false; m_bIsBeingAnimated = false;
if (m_fUpdateCallback)
m_fUpdateCallback(this);
if (endCallback) if (endCallback)
onAnimationEnd(); onAnimationEnd();
} }

View File

@@ -106,6 +106,11 @@ CBox& CBox::expand(const double& value) {
w += value * 2.0; w += value * 2.0;
h += value * 2.0; h += value * 2.0;
if (w <= 0 || h <= 0) {
w = 0;
h = 0;
}
return *this; return *this;
} }
@@ -116,6 +121,22 @@ CBox& CBox::noNegativeSize() {
return *this; return *this;
} }
CBox CBox::intersection(const CBox other) const {
const float newX = std::max(x, other.x);
const float newY = std::max(y, other.y);
const float newBottom = std::min(y + h, other.y + other.h);
const float newRight = std::min(x + w, other.x + other.w);
float newW = newRight - newX;
float newH = newBottom - newY;
if (newW <= 0 || newH <= 0) {
newW = 0;
newH = 0;
}
return {newX, newY, newW, newH};
}
CBox CBox::roundInternal() { CBox CBox::roundInternal() {
float newW = x + w - std::floor(x); float newW = x + w - std::floor(x);
float newH = y + h - std::floor(y); float newH = y + h - std::floor(y);

View File

@@ -54,6 +54,7 @@ class CBox {
CBox& noNegativeSize(); CBox& noNegativeSize();
CBox copy() const; CBox copy() const;
CBox intersection(const CBox other) const;
SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box

View File

@@ -21,6 +21,6 @@ CColor::CColor(uint64_t hex) {
this->a = ALPHA(hex); this->a = ALPHA(hex);
} }
uint64_t CColor::getAsHex() { uint32_t CColor::getAsHex() {
return ((int)a) * 0x1000000 + ((int)r) * 0x10000 + ((int)g) * 0x100 + ((int)b) * 0x1; return (uint32_t)(a * 255.f) * 0x1000000 + (uint32_t)(r * 255.f) * 0x10000 + (uint32_t)(g * 255.f) * 0x100 + (uint32_t)(b * 255.f) * 0x1;
} }

View File

@@ -10,7 +10,7 @@ class CColor {
float r = 0, g = 0, b = 0, a = 1.f; float r = 0, g = 0, b = 0, a = 1.f;
uint64_t getAsHex(); uint32_t getAsHex();
CColor operator-(const CColor& c2) const { CColor operator-(const CColor& c2) const {
return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a); return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a);

View File

@@ -289,9 +289,9 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_pLastMonitor)
return WORKSPACE_INVALID; return WORKSPACE_INVALID;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
if (!PWORKSPACE) if (!valid(PWORKSPACE))
return WORKSPACE_INVALID; return WORKSPACE_INVALID;
const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.iID); const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.iID);
@@ -347,7 +347,8 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
std::sort(namedWSes.begin(), namedWSes.end()); std::sort(namedWSes.begin(), namedWSes.end());
// Just take a blind guess at where we'll probably end up // Just take a blind guess at where we'll probably end up
int predictedWSID = g_pCompositor->m_pLastMonitor->activeWorkspace + remains; int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1;
int predictedWSID = activeWSID + remains;
int remainingWSes = 0; int remainingWSes = 0;
char walkDir = in[1]; char walkDir = in[1];
@@ -355,20 +356,20 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
predictedWSID = std::max(predictedWSID, 0); predictedWSID = std::max(predictedWSID, 0);
// Count how many invalidWSes are in between (how bad the prediction was) // Count how many invalidWSes are in between (how bad the prediction was)
int beginID = in[1] == '+' ? g_pCompositor->m_pLastMonitor->activeWorkspace + 1 : predictedWSID; int beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID;
int endID = in[1] == '+' ? predictedWSID : g_pCompositor->m_pLastMonitor->activeWorkspace; int endID = in[1] == '+' ? predictedWSID : activeWSID;
auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >=
for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) {
remainingWSes++; remainingWSes++;
} }
// Handle named workspaces. They are treated like always before other workspaces // Handle named workspaces. They are treated like always before other workspaces
if (g_pCompositor->m_pLastMonitor->activeWorkspace < 0) { if (activeWSID < 0) {
// Behaviour similar to 'm' // Behaviour similar to 'm'
// Find current // Find current
int currentItem = -1; int currentItem = -1;
for (size_t i = 0; i < namedWSes.size(); i++) { for (size_t i = 0; i < namedWSes.size(); i++) {
if (namedWSes[i] == g_pCompositor->m_pLastMonitor->activeWorkspace) { if (namedWSes[i] == activeWSID) {
currentItem = i; currentItem = i;
break; break;
} }
@@ -473,9 +474,10 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size(); remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size();
// get the current item // get the current item
int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1;
int currentItem = -1; int currentItem = -1;
for (size_t i = 0; i < validWSes.size(); i++) { for (size_t i = 0; i < validWSes.size(); i++) {
if (validWSes[i] == g_pCompositor->m_pLastMonitor->activeWorkspace) { if (validWSes[i] == activeWSID) {
currentItem = i; currentItem = i;
break; break;
} }
@@ -496,7 +498,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
} else { } else {
if (in[0] == '+' || in[0] == '-') { if (in[0] == '+' || in[0] == '-') {
if (g_pCompositor->m_pLastMonitor) { if (g_pCompositor->m_pLastMonitor) {
const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspaceID());
if (!PLUSMINUSRESULT.has_value()) if (!PLUSMINUSRESULT.has_value())
return WORKSPACE_INVALID; return WORKSPACE_INVALID;

View File

@@ -169,8 +169,11 @@ void CMonitor::onConnect(bool noRule) {
setupDefaultWS(monitorRule); setupDefaultWS(monitorRule);
for (auto& ws : g_pCompositor->m_vWorkspaces) { for (auto& ws : g_pCompositor->m_vWorkspaces) {
if (!valid(ws))
continue;
if (ws->m_szLastMonitor == szName || g_pCompositor->m_vMonitors.size() == 1 /* avoid lost workspaces on recover */) { if (ws->m_szLastMonitor == szName || g_pCompositor->m_vMonitors.size() == 1 /* avoid lost workspaces on recover */) {
g_pCompositor->moveWorkspaceToMonitor(ws.get(), this); g_pCompositor->moveWorkspaceToMonitor(ws, this);
ws->startAnim(true, true, true); ws->startAnim(true, true, true);
ws->m_szLastMonitor = ""; ws->m_szLastMonitor = "";
} }
@@ -281,10 +284,10 @@ void CMonitor::onDisconnect(bool destroy) {
BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f); BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
// move workspaces // move workspaces
std::deque<CWorkspace*> wspToMove; std::deque<PHLWORKSPACE> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) { if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) {
wspToMove.push_back(w.get()); wspToMove.push_back(w);
} }
} }
@@ -299,7 +302,9 @@ void CMonitor::onDisconnect(bool destroy) {
g_pCompositor->m_pLastMonitor = nullptr; g_pCompositor->m_pLastMonitor = nullptr;
} }
activeWorkspace = -1; if (activeWorkspace)
activeWorkspace->m_bVisible = false;
activeWorkspace.reset();
if (!destroy) if (!destroy)
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output); wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
@@ -310,7 +315,7 @@ void CMonitor::onDisconnect(bool destroy) {
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect"); Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor == this) if (g_pCompositor->m_pLastMonitor == this)
g_pCompositor->setActiveMonitor(BACKUPMON); g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput);
if (g_pHyprRenderer->m_pMostHzMonitor == this) { if (g_pHyprRenderer->m_pMostHzMonitor == this) {
int mostHz = 0; int mostHz = 0;
@@ -403,19 +408,20 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
if (PNEWWORKSPACE) { if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor // workspace exists, move it to the newly connected monitor
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this); g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this);
activeWorkspace = PNEWWORKSPACE->m_iID; activeWorkspace = PNEWWORKSPACE;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
PNEWWORKSPACE->startAnim(true, true, true); PNEWWORKSPACE->startAnim(true, true, true);
} else { } else {
if (newDefaultWorkspaceName == "") if (newDefaultWorkspaceName == "")
newDefaultWorkspaceName = std::to_string(WORKSPACEID); newDefaultWorkspaceName = std::to_string(WORKSPACEID);
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(WORKSPACEID, ID, newDefaultWorkspaceName)).get(); PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(CWorkspace::create(WORKSPACEID, ID, newDefaultWorkspaceName));
} }
activeWorkspace = PNEWWORKSPACE->m_iID; activeWorkspace = PNEWWORKSPACE;
PNEWWORKSPACE->setActive(true); PNEWWORKSPACE->setActive(true);
PNEWWORKSPACE->m_bVisible = true;
PNEWWORKSPACE->m_szLastMonitor = ""; PNEWWORKSPACE->m_szLastMonitor = "";
} }
@@ -481,10 +487,10 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
} }
// move all the WS // move all the WS
std::deque<CWorkspace*> wspToMove; std::deque<PHLWORKSPACE> wspToMove;
for (auto& w : g_pCompositor->m_vWorkspaces) { for (auto& w : g_pCompositor->m_vWorkspaces) {
if (w->m_iMonitorID == ID) { if (w->m_iMonitorID == ID) {
wspToMove.push_back(w.get()); wspToMove.push_back(w);
} }
} }
@@ -493,7 +499,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
w->startAnim(true, true, true); w->startAnim(true, true, true);
} }
activeWorkspace = -1; activeWorkspace.reset();
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output); wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
@@ -532,24 +538,26 @@ float CMonitor::getDefaultScale() {
return 1; return 1;
} }
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove, bool noFocus) { void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bool noMouseMove, bool noFocus) {
if (!pWorkspace) if (!pWorkspace)
return; return;
if (pWorkspace->m_bIsSpecialWorkspace) { if (pWorkspace->m_bIsSpecialWorkspace) {
if (specialWorkspaceID != pWorkspace->m_iID) { if (activeSpecialWorkspace != pWorkspace) {
Debug::log(LOG, "changeworkspace on special, togglespecialworkspace to id {}", pWorkspace->m_iID); Debug::log(LOG, "changeworkspace on special, togglespecialworkspace to id {}", pWorkspace->m_iID);
g_pKeybindManager->m_mDispatchers["togglespecialworkspace"](pWorkspace->m_szName == "special" ? "" : pWorkspace->m_szName); setSpecialWorkspace(pWorkspace);
} }
return; return;
} }
if (pWorkspace->m_iID == activeWorkspace) if (pWorkspace == activeWorkspace)
return; return;
const auto POLDWORKSPACE = g_pCompositor->getWorkspaceByID(activeWorkspace); const auto POLDWORKSPACE = activeWorkspace;
POLDWORKSPACE->m_bVisible = false;
pWorkspace->m_bVisible = true;
activeWorkspace = pWorkspace->m_iID; activeWorkspace = pWorkspace;
if (!internal) { if (!internal) {
const auto ANIMTOLEFT = pWorkspace->m_iID > POLDWORKSPACE->m_iID; const auto ANIMTOLEFT = pWorkspace->m_iID > POLDWORKSPACE->m_iID;
@@ -558,12 +566,12 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
// move pinned windows // move pinned windows
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == POLDWORKSPACE->m_iID && w->m_bPinned) { if (w->m_pWorkspace == POLDWORKSPACE && w->m_bPinned)
w->m_iWorkspaceID = pWorkspace->m_iID; w->moveToWorkspace(pWorkspace);
}
} }
if (!noFocus && !g_pCompositor->m_pLastMonitor->specialWorkspaceID) { if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace &&
!(g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse"); static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
CWindow* pWindow = pWorkspace->getLastFocusedWindow(); CWindow* pWindow = pWorkspace->getLastFocusedWindow();
@@ -599,37 +607,36 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
g_pCompositor->updateSuspendedStates(); g_pCompositor->updateSuspendedStates();
if (specialWorkspaceID) { if (activeSpecialWorkspace)
const auto PSPECIALWS = g_pCompositor->getWorkspaceByID(specialWorkspaceID); g_pCompositor->updateFullscreenFadeOnWorkspace(activeSpecialWorkspace);
if (PSPECIALWS->m_bHasFullscreenWindow)
g_pCompositor->updateFullscreenFadeOnWorkspace(PSPECIALWS);
}
} }
void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) { void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) {
changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus); changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus);
} }
void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) { void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
g_pHyprRenderer->damageMonitor(this); g_pHyprRenderer->damageMonitor(this);
if (!pWorkspace) { if (!pWorkspace) {
// remove special if exists // remove special if exists
if (const auto EXISTINGSPECIAL = g_pCompositor->getWorkspaceByID(specialWorkspaceID); EXISTINGSPECIAL) { if (activeSpecialWorkspace) {
EXISTINGSPECIAL->startAnim(false, false); activeSpecialWorkspace->m_bVisible = false;
activeSpecialWorkspace->startAnim(false, false);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + szName}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + szName});
} }
specialWorkspaceID = 0; activeSpecialWorkspace.reset();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(activeWorkspace); if (!(g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) {
if (const auto PLAST = PWORKSPACE->getLastFocusedWindow(); PLAST) if (const auto PLAST = activeWorkspace->getLastFocusedWindow(); PLAST)
g_pCompositor->focusWindow(PLAST); g_pCompositor->focusWindow(PLAST);
else else
g_pInputManager->refocus(); g_pInputManager->refocus();
}
g_pCompositor->updateFullscreenFadeOnWorkspace(PWORKSPACE); g_pCompositor->updateFullscreenFadeOnWorkspace(activeWorkspace);
g_pConfigManager->ensureVRR(this); g_pConfigManager->ensureVRR(this);
@@ -638,20 +645,20 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
return; return;
} }
if (specialWorkspaceID) { if (activeSpecialWorkspace) {
if (const auto EXISTINGSPECIAL = g_pCompositor->getWorkspaceByID(specialWorkspaceID); EXISTINGSPECIAL) activeSpecialWorkspace->m_bVisible = false;
EXISTINGSPECIAL->startAnim(false, false); activeSpecialWorkspace->startAnim(false, false);
} }
bool animate = true; bool animate = true;
//close if open elsewhere //close if open elsewhere
const auto PMONITORWORKSPACEOWNER = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); const auto PMONITORWORKSPACEOWNER = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
if (PMONITORWORKSPACEOWNER->specialWorkspaceID == pWorkspace->m_iID) { if (PMONITORWORKSPACEOWNER->activeSpecialWorkspace == pWorkspace) {
PMONITORWORKSPACEOWNER->specialWorkspaceID = 0; PMONITORWORKSPACEOWNER->activeSpecialWorkspace.reset();
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMONITORWORKSPACEOWNER->szName}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMONITORWORKSPACEOWNER->szName});
const auto PACTIVEWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITORWORKSPACEOWNER->activeWorkspace); const auto PACTIVEWORKSPACE = PMONITORWORKSPACEOWNER->activeWorkspace;
g_pCompositor->updateFullscreenFadeOnWorkspace(PACTIVEWORKSPACE); g_pCompositor->updateFullscreenFadeOnWorkspace(PACTIVEWORKSPACE);
animate = false; animate = false;
@@ -659,14 +666,16 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
// open special // open special
pWorkspace->m_iMonitorID = ID; pWorkspace->m_iMonitorID = ID;
specialWorkspaceID = pWorkspace->m_iID; activeSpecialWorkspace = pWorkspace;
activeSpecialWorkspace->m_bVisible = true;
if (animate) if (animate)
pWorkspace->startAnim(true, true); pWorkspace->startAnim(true, true);
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iWorkspaceID == pWorkspace->m_iID) { if (w->m_pWorkspace == pWorkspace) {
w->m_iMonitorID = ID; w->m_iMonitorID = ID;
w->updateSurfaceScaleTransformDetails(); w->updateSurfaceScaleTransformDetails();
w->setAnimationsToMove();
const auto MIDDLE = w->middle(); const auto MIDDLE = w->middle();
if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) { if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) {
@@ -688,10 +697,12 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
if (!(g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) {
if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST) if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST)
g_pCompositor->focusWindow(PLAST); g_pCompositor->focusWindow(PLAST);
else else
g_pInputManager->refocus(); g_pInputManager->refocus();
}
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
@@ -728,6 +739,13 @@ void CMonitor::updateMatrix() {
} }
} }
int64_t CMonitor::activeWorkspaceID() {
return activeWorkspace ? activeWorkspace->m_iID : 0;
}
int64_t CMonitor::activeSpecialWorkspaceID() {
return activeSpecialWorkspace ? activeSpecialWorkspace->m_iID : 0;
}
CMonitorState::CMonitorState(CMonitor* owner) { CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner; m_pOwner = owner;
wlr_output_state_init(&m_state); wlr_output_state_init(&m_state);

View File

@@ -58,7 +58,8 @@ class CMonitor {
bool primary = false; bool primary = false;
uint64_t ID = -1; uint64_t ID = -1;
int activeWorkspace = -1; PHLWORKSPACE activeWorkspace = nullptr;
PHLWORKSPACE activeSpecialWorkspace = nullptr;
float setScale = 1; // scale set by cfg float setScale = 1; // scale set by cfg
float scale = 1; // real scale float scale = 1; // real scale
@@ -119,9 +120,6 @@ class CMonitor {
bool frameScheduledWhileBusy = false; bool frameScheduledWhileBusy = false;
} tearingState; } tearingState;
// for the special workspace. 0 means not open.
int specialWorkspaceID = 0;
std::array<std::vector<std::unique_ptr<SLayerSurface>>, 4> m_aLayerSurfaceLayers; std::array<std::vector<std::unique_ptr<SLayerSurface>>, 4> m_aLayerSurfaceLayers;
DYNLISTENER(monitorFrame); DYNLISTENER(monitorFrame);
@@ -142,13 +140,15 @@ class CMonitor {
bool isMirror(); bool isMirror();
bool matchesStaticSelector(const std::string& selector) const; bool matchesStaticSelector(const std::string& selector) const;
float getDefaultScale(); float getDefaultScale();
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false); void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false); void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void setSpecialWorkspace(CWorkspace* const pWorkspace); void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace);
void setSpecialWorkspace(const int& id); void setSpecialWorkspace(const int& id);
void moveTo(const Vector2D& pos); void moveTo(const Vector2D& pos);
Vector2D middle(); Vector2D middle();
void updateMatrix(); void updateMatrix();
int64_t activeWorkspaceID();
int64_t activeSpecialWorkspaceID();
bool m_bEnabled = false; bool m_bEnabled = false;
bool m_bRenderingInitPassed = false; bool m_bRenderingInitPassed = false;

View File

@@ -3,16 +3,18 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
SLayerSurface::SLayerSurface() { SLayerSurface::SLayerSurface() {
alpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeLayers"), nullptr, AVARDAMAGE_ENTIRE); alpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), this, AVARDAMAGE_ENTIRE);
realPosition.create(g_pConfigManager->getAnimationPropertyConfig("layers"), nullptr, AVARDAMAGE_ENTIRE); realPosition.create(g_pConfigManager->getAnimationPropertyConfig("layersIn"), this, AVARDAMAGE_ENTIRE);
realSize.create(g_pConfigManager->getAnimationPropertyConfig("layers"), nullptr, AVARDAMAGE_ENTIRE); realSize.create(g_pConfigManager->getAnimationPropertyConfig("layersIn"), this, AVARDAMAGE_ENTIRE);
alpha.m_pLayer = this;
realPosition.m_pLayer = this;
realSize.m_pLayer = this;
alpha.registerVar(); alpha.registerVar();
realPosition.registerVar(); realPosition.registerVar();
realSize.registerVar(); realSize.registerVar();
alpha.setUpdateCallback([this](void*) {
if (dimAround)
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(monitorID));
});
alpha.setValueAndWarp(0.f); alpha.setValueAndWarp(0.f);
} }
@@ -29,6 +31,7 @@ void SLayerSurface::applyRules() {
forceBlur = false; forceBlur = false;
ignoreAlpha = false; ignoreAlpha = false;
ignoreAlphaValue = 0.f; ignoreAlphaValue = 0.f;
dimAround = false;
xray = -1; xray = -1;
animationStyle.reset(); animationStyle.reset();
@@ -37,6 +40,8 @@ void SLayerSurface::applyRules() {
noAnimations = true; noAnimations = true;
else if (rule.rule == "blur") else if (rule.rule == "blur")
forceBlur = true; forceBlur = true;
else if (rule.rule == "blurpopups")
forceBlurPopups = true;
else if (rule.rule.starts_with("ignorealpha") || rule.rule.starts_with("ignorezero")) { else if (rule.rule.starts_with("ignorealpha") || rule.rule.starts_with("ignorezero")) {
const auto FIRST_SPACE_POS = rule.rule.find_first_of(' '); const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
std::string alphaValue = ""; std::string alphaValue = "";
@@ -48,6 +53,8 @@ void SLayerSurface::applyRules() {
if (!alphaValue.empty()) if (!alphaValue.empty())
ignoreAlphaValue = std::stof(alphaValue); ignoreAlphaValue = std::stof(alphaValue);
} catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); } } catch (...) { Debug::log(ERR, "Invalid value passed to ignoreAlpha"); }
} else if (rule.rule == "dimaround") {
dimAround = true;
} else if (rule.rule.starts_with("xray")) { } else if (rule.rule.starts_with("xray")) {
CVarList vars{rule.rule, 0, ' '}; CVarList vars{rule.rule, 0, ' '};
try { try {
@@ -62,13 +69,37 @@ void SLayerSurface::applyRules() {
void SLayerSurface::startAnimation(bool in, bool instant) { void SLayerSurface::startAnimation(bool in, bool instant) {
const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle); const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle);
if (in) {
realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn");
realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn");
alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn");
} else {
realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut");
realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut");
alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut");
}
if (ANIMSTYLE == "slide") { if (ANIMSTYLE.starts_with("slide")) {
// get closest edge // get closest edge
const auto MIDDLE = geometry.middle(); const auto MIDDLE = geometry.middle();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE); const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE);
int force = -1;
CVarList args(ANIMSTYLE, 0, 's');
if (args.size() > 1) {
const auto ARG2 = args[1];
if (ARG2 == "top")
force = 0;
else if (ARG2 == "bottom")
force = 1;
else if (ARG2 == "left")
force = 2;
else if (ARG2 == "right")
force = 3;
}
const std::array<Vector2D, 4> edgePoints = { const std::array<Vector2D, 4> edgePoints = {
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y},
@@ -77,7 +108,8 @@ void SLayerSurface::startAnimation(bool in, bool instant) {
}; };
float closest = std::numeric_limits<float>::max(); float closest = std::numeric_limits<float>::max();
size_t leader = 0; int leader = force;
if (leader == -1) {
for (size_t i = 0; i < 4; ++i) { for (size_t i = 0; i < 4; ++i) {
float dist = MIDDLE.distance(edgePoints[i]); float dist = MIDDLE.distance(edgePoints[i]);
if (dist < closest) { if (dist < closest) {
@@ -85,9 +117,11 @@ void SLayerSurface::startAnimation(bool in, bool instant) {
closest = dist; closest = dist;
} }
} }
}
realSize.setValueAndWarp(geometry.size()); realSize.setValueAndWarp(geometry.size());
alpha.setValueAndWarp(1.f); alpha.setValueAndWarp(in ? 0.f : 1.f);
alpha = in ? 1.f : 0.f;
Vector2D prePos; Vector2D prePos;
@@ -98,7 +132,7 @@ void SLayerSurface::startAnimation(bool in, bool instant) {
break; break;
case 1: case 1:
// BOTTOM // BOTTOM
prePos = {geometry.x, PMONITOR->vecPosition.y + PMONITOR->vecPosition.y}; prePos = {geometry.x, PMONITOR->vecPosition.y + PMONITOR->vecSize.y};
break; break;
case 2: case 2:
// LEFT // LEFT
@@ -167,6 +201,16 @@ bool SLayerSurface::isFadedOut() {
return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated(); return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated();
} }
int SLayerSurface::popupsCount() {
if (!layerSurface || !mapped || fadingOut)
return 0;
int no = 0;
wlr_layer_surface_v1_for_each_popup_surface(
layerSurface, [](wlr_surface* s, int x, int y, void* data) { *(int*)data += 1; }, &no);
return no;
}
void SKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { void SKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
xkb_state_unref(xkbTranslationState); xkb_state_unref(xkbTranslationState);

View File

@@ -3,7 +3,7 @@
#include "../events/Events.hpp" #include "../events/Events.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "wlr-layer-shell-unstable-v1-protocol.h" #include "wlr-layer-shell-unstable-v1-protocol.h"
#include "../Window.hpp" #include "../desktop/Window.hpp"
#include "../desktop/Subsurface.hpp" #include "../desktop/Subsurface.hpp"
#include "../desktop/Popup.hpp" #include "../desktop/Popup.hpp"
#include "AnimatedVariable.hpp" #include "AnimatedVariable.hpp"
@@ -22,6 +22,7 @@ struct SLayerSurface {
void applyRules(); void applyRules();
void startAnimation(bool in, bool instant = false); void startAnimation(bool in, bool instant = false);
bool isFadedOut(); bool isFadedOut();
int popupsCount();
CAnimatedVariable<Vector2D> realPosition; CAnimatedVariable<Vector2D> realPosition;
CAnimatedVariable<Vector2D> realSize; CAnimatedVariable<Vector2D> realSize;
@@ -58,9 +59,11 @@ struct SLayerSurface {
bool noAnimations = false; bool noAnimations = false;
bool forceBlur = false; bool forceBlur = false;
bool forceBlurPopups = false;
int xray = -1; int xray = -1;
bool ignoreAlpha = false; bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f; float ignoreAlphaValue = 0.f;
bool dimAround = false;
std::optional<std::string> animationStyle; std::optional<std::string> animationStyle;
@@ -217,6 +220,8 @@ struct STablet {
std::string boundOutput = ""; std::string boundOutput = "";
CBox activeArea;
// //
bool operator==(const STablet& b) const { bool operator==(const STablet& b) const {
return wlrDevice == b.wlrDevice; return wlrDevice == b.wlrDevice;
@@ -267,6 +272,7 @@ struct STabletPad {
struct SIdleInhibitor { struct SIdleInhibitor {
wlr_idle_inhibitor_v1* pWlrInhibitor = nullptr; wlr_idle_inhibitor_v1* pWlrInhibitor = nullptr;
CWindow* pWindow = nullptr; CWindow* pWindow = nullptr;
HOOK_CALLBACK_FN* onWindowDestroy = nullptr;
DYNLISTENER(Destroy); DYNLISTENER(Destroy);
@@ -276,33 +282,18 @@ struct SIdleInhibitor {
}; };
struct SSwipeGesture { struct SSwipeGesture {
CWorkspace* pWorkspaceBegin = nullptr; PHLWORKSPACE pWorkspaceBegin = nullptr;
double delta = 0; double delta = 0;
int initialDirection = 0; int initialDirection = 0;
float avgSpeed = 0; float avgSpeed = 0;
int speedPoints = 0; int speedPoints = 0;
int touch_id = 0;
CMonitor* pMonitor = nullptr; CMonitor* pMonitor = nullptr;
}; };
struct STextInputV1;
struct STextInput {
wlr_text_input_v3* pWlrInput = nullptr;
STextInputV1* pV1Input = nullptr;
wlr_surface* pPendingSurface = nullptr;
DYNLISTENER(textInputEnable);
DYNLISTENER(textInputDisable);
DYNLISTENER(textInputCommit);
DYNLISTENER(textInputDestroy);
DYNLISTENER(pendingSurfaceDestroy);
};
struct SIMEKbGrab { struct SIMEKbGrab {
wlr_input_method_keyboard_grab_v2* pWlrKbGrab = nullptr; wlr_input_method_keyboard_grab_v2* pWlrKbGrab = nullptr;
@@ -311,26 +302,6 @@ struct SIMEKbGrab {
DYNLISTENER(grabDestroy); DYNLISTENER(grabDestroy);
}; };
struct SIMEPopup {
wlr_input_popup_surface_v2* pSurface = nullptr;
int x, y;
int realX, realY;
bool visible;
Vector2D lastSize;
DYNLISTENER(mapPopup);
DYNLISTENER(unmapPopup);
DYNLISTENER(destroyPopup);
DYNLISTENER(commitPopup);
DYNLISTENER(focusedSurfaceUnmap);
bool operator==(const SIMEPopup& other) const {
return pSurface == other.pSurface;
}
};
struct STouchDevice { struct STouchDevice {
wlr_input_device* pWlrDevice = nullptr; wlr_input_device* pWlrDevice = nullptr;

View File

@@ -1,8 +1,9 @@
#include "HyprError.hpp" #include "HyprError.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
CHyprError::CHyprError() { CHyprError::CHyprError() {
m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_NONE); m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE);
m_fFadeOpacity.registerVar(); m_fFadeOpacity.registerVar();
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
@@ -57,7 +58,11 @@ void CHyprError::createQueued() {
cairo_paint(CAIRO); cairo_paint(CAIRO);
cairo_restore(CAIRO); cairo_restore(CAIRO);
const auto LINECOUNT = 1 + std::count(m_szQueued.begin(), m_szQueued.end(), '\n'); const auto LINECOUNT = Hyprlang::INT{1} + std::count(m_szQueued.begin(), m_szQueued.end(), '\n');
static auto LINELIMIT = CConfigValue<Hyprlang::INT>("debug:error_limit");
const auto VISLINECOUNT = std::min(LINECOUNT, *LINELIMIT);
const auto EXTRALINES = (VISLINECOUNT < LINECOUNT) ? 1 : 0;
const double DEGREES = M_PI / 180.0; const double DEGREES = M_PI / 180.0;
@@ -66,7 +71,7 @@ void CHyprError::createQueued() {
const double X = PAD; const double X = PAD;
const double Y = PAD; const double Y = PAD;
const double WIDTH = PMONITOR->vecPixelSize.x - PAD * 2; const double WIDTH = PMONITOR->vecPixelSize.x - PAD * 2;
const double HEIGHT = (FONTSIZE + 2 * (FONTSIZE / 10.0)) * LINECOUNT + 3; const double HEIGHT = (FONTSIZE + 2 * (FONTSIZE / 10.0)) * (VISLINECOUNT + EXTRALINES) + 3;
const double RADIUS = PAD > HEIGHT / 2 ? HEIGHT / 2 - 1 : PAD; const double RADIUS = PAD > HEIGHT / 2 ? HEIGHT / 2 - 1 : PAD;
m_bDamageBox = {0, 0, (int)PMONITOR->vecPixelSize.x, (int)HEIGHT + (int)PAD * 2}; m_bDamageBox = {0, 0, (int)PMONITOR->vecPixelSize.x, (int)HEIGHT + (int)PAD * 2};
@@ -92,7 +97,8 @@ void CHyprError::createQueued() {
cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a); cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a);
float yoffset = FONTSIZE; float yoffset = FONTSIZE;
while (m_szQueued != "") { int renderedcnt = 0;
while (m_szQueued != "" && renderedcnt < VISLINECOUNT) {
std::string current = m_szQueued.substr(0, m_szQueued.find('\n')); std::string current = m_szQueued.substr(0, m_szQueued.find('\n'));
if (const auto NEWLPOS = m_szQueued.find('\n'); NEWLPOS != std::string::npos) if (const auto NEWLPOS = m_szQueued.find('\n'); NEWLPOS != std::string::npos)
m_szQueued = m_szQueued.substr(NEWLPOS + 1); m_szQueued = m_szQueued.substr(NEWLPOS + 1);
@@ -101,7 +107,14 @@ void CHyprError::createQueued() {
cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1); cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1);
cairo_show_text(CAIRO, current.c_str()); cairo_show_text(CAIRO, current.c_str());
yoffset += FONTSIZE + (FONTSIZE / 10.f); yoffset += FONTSIZE + (FONTSIZE / 10.f);
renderedcnt++;
} }
if (VISLINECOUNT < LINECOUNT) {
std::string moreString = std::format("({} more...)", LINECOUNT - VISLINECOUNT);
cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1);
cairo_show_text(CAIRO, moreString.c_str());
}
m_szQueued = "";
cairo_surface_flush(CAIROSURFACE); cairo_surface_flush(CAIROSURFACE);

View File

@@ -105,7 +105,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (m->specialWorkspaceID == pNode->workspaceID) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) {
PMONITOR = m.get(); PMONITOR = m.get();
break; break;
} }
@@ -149,17 +149,16 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN); auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT); auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
CBox nodeBox = pNode->box; CBox nodeBox = pNode->box;
nodeBox.round(); nodeBox.round();
PWINDOW->m_vSize = nodeBox.size(); PWINDOW->m_vSize = nodeBox.size();
PWINDOW->m_vPosition = nodeBox.pos(); PWINDOW->m_vPosition = nodeBox.pos();
const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->m_iWorkspaceID); const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->workspaceID());
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() &&
(NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { (NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2); PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2);
PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true); PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true);
@@ -216,7 +215,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
calcPos = calcPos + RESERVED.topLeft; calcPos = calcPos + RESERVED.topLeft;
calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight); calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight);
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && !PWINDOW->m_bIsFullscreen) { if (PWINDOW->onSpecialWorkspace() && !PWINDOW->m_bIsFullscreen) {
// if special, we adjust the coords a bit // if special, we adjust the coords a bit
static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("dwindle:special_scale_factor"); static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("dwindle:special_scale_factor");
@@ -265,7 +264,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
overrideDirection = direction; overrideDirection = direction;
// Populate the node with our window's data // Populate the node with our window's data
PNODE->workspaceID = pWindow->m_iWorkspaceID; PNODE->workspaceID = pWindow->workspaceID();
PNODE->pWindow = pWindow; PNODE->pWindow = pWindow;
PNODE->isNode = false; PNODE->isNode = false;
PNODE->layout = this; PNODE->layout = this;
@@ -276,7 +275,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS); const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);
if (PMONITOR->ID == MONFROMCURSOR->ID && if (PMONITOR->ID == MONFROMCURSOR->ID &&
(PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) { (PNODE->workspaceID == PMONITOR->activeWorkspaceID() || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->activeSpecialWorkspace)) && !*PUSEACTIVE) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS)); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS));
if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR)) if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
@@ -284,7 +283,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
} else if (*PUSEACTIVE) { } else if (*PUSEACTIVE) {
if (g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow && if (g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow &&
g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) { g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace && g_pCompositor->m_pLastWindow->m_bIsMapped) {
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow); OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
} else { } else {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS)); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS));
@@ -294,7 +293,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS); OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS);
} else } else
OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID); OPENINGON = getFirstNodeOnWorkspace(pWindow->workspaceID());
Debug::log(LOG, "OPENINGON: {}, Monitor: {}", OPENINGON, PMONITOR->ID); Debug::log(LOG, "OPENINGON: {}, Monitor: {}", OPENINGON, PMONITOR->ID);
@@ -538,58 +537,35 @@ void CHyprDwindleLayout::onWindowRemovedTiling(CWindow* pWindow) {
void CHyprDwindleLayout::recalculateMonitor(const int& monid) { void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
if (!PMONITOR) if (!PMONITOR || !PMONITOR->activeWorkspace)
return; // ??? return; // ???
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
if (!PWORKSPACE)
return;
g_pHyprRenderer->damageMonitor(PMONITOR); g_pHyprRenderer->damageMonitor(PMONITOR);
if (PMONITOR->specialWorkspaceID) { if (PMONITOR->activeSpecialWorkspace)
const auto PSPECIALWS = g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID); calculateWorkspace(PMONITOR->activeSpecialWorkspace);
if (PSPECIALWS->m_bHasFullscreenWindow) { calculateWorkspace(PMONITOR->activeWorkspace);
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PSPECIALWS->m_iID);
if (PSPECIALWS->m_efFullscreenMode == FULLSCREEN_FULL) {
PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
PFULLWINDOW->m_vRealSize = PMONITOR->vecSize;
} else if (PSPECIALWS->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
SDwindleNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW;
fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
fakeNode.workspaceID = PSPECIALWS->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.box.pos();
PFULLWINDOW->m_vSize = fakeNode.box.size();
fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode);
}
} }
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->specialWorkspaceID); void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
if (TOPNODE && PMONITOR) { if (!PMONITOR)
TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight}; return;
TOPNODE->recalcSizePosRecursive();
}
}
if (PWORKSPACE->m_bHasFullscreenWindow) { if (pWorkspace->m_bHasFullscreenWindow) {
// massive hack from the fullscreen func // massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID);
if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { if (pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) {
PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; PFULLWINDOW->m_vRealSize = PMONITOR->vecSize;
} else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { } else if (pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
SDwindleNodeData fakeNode; SDwindleNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW; fakeNode.pWindow = PFULLWINDOW;
fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight}; fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
fakeNode.workspaceID = PWORKSPACE->m_iID; fakeNode.workspaceID = pWorkspace->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.box.pos(); PFULLWINDOW->m_vPosition = fakeNode.box.pos();
PFULLWINDOW->m_vSize = fakeNode.box.size(); PFULLWINDOW->m_vSize = fakeNode.box.size();
fakeNode.ignoreFullscreenChecks = true; fakeNode.ignoreFullscreenChecks = true;
@@ -597,12 +573,13 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
applyNodeDataToWindow(&fakeNode); applyNodeDataToWindow(&fakeNode);
} }
// if has fullscreen, don't calculate the rest
return; return;
} }
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace); const auto TOPNODE = getMasterNodeOnWorkspace(pWorkspace->m_iID);
if (TOPNODE && PMONITOR) { if (TOPNODE) {
TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight}; TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
TOPNODE->recalcSizePosRecursive(); TOPNODE->recalcSizePosRecursive();
} }
@@ -817,7 +794,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
return; // ignore return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = pWindow->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && on) { if (PWORKSPACE->m_bHasFullscreenWindow && on) {
// if the window wants to be fullscreen but there already is one, // if the window wants to be fullscreen but there already is one,
@@ -872,7 +849,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
SDwindleNodeData fakeNode; SDwindleNodeData fakeNode;
fakeNode.pWindow = pWindow; fakeNode.pWindow = pWindow;
fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight}; fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
fakeNode.workspaceID = pWindow->m_iWorkspaceID; fakeNode.workspaceID = pWindow->workspaceID();
pWindow->m_vPosition = fakeNode.box.pos(); pWindow->m_vPosition = fakeNode.box.pos();
pWindow->m_vSize = fakeNode.box.size(); pWindow->m_vSize = fakeNode.box.size();
fakeNode.ignoreFullscreenChecks = true; fakeNode.ignoreFullscreenChecks = true;
@@ -941,6 +918,8 @@ void CHyprDwindleLayout::moveWindowTo(CWindow* pWindow, const std::string& dir)
default: UNREACHABLE(); default: UNREACHABLE();
} }
pWindow->setAnimationsToMove();
onWindowRemovedTiling(pWindow); onWindowRemovedTiling(pWindow);
m_vOverrideFocalPoint = focalPoint; m_vOverrideFocalPoint = focalPoint;
@@ -983,9 +962,12 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
if (PNODE->workspaceID != PNODE2->workspaceID) { if (PNODE->workspaceID != PNODE2->workspaceID) {
std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID); std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID);
std::swap(pWindow2->m_iWorkspaceID, pWindow->m_iWorkspaceID); std::swap(pWindow2->m_pWorkspace, pWindow->m_pWorkspace);
} }
pWindow->setAnimationsToMove();
pWindow2->setAnimationsToMove();
// recalc the workspace // recalc the workspace
getMasterNodeOnWorkspace(PNODE->workspaceID)->recalcSizePosRecursive(); getMasterNodeOnWorkspace(PNODE->workspaceID)->recalcSizePosRecursive();
@@ -1128,7 +1110,7 @@ void CHyprDwindleLayout::onDisable() {
m_lDwindleNodesData.clear(); m_lDwindleNodesData.clear();
} }
Vector2D CHyprDwindleLayout::predictSizeForNewWindow() { Vector2D CHyprDwindleLayout::predictSizeForNewWindowTiled() {
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_pLastMonitor)
return {}; return {};
@@ -1136,7 +1118,7 @@ Vector2D CHyprDwindleLayout::predictSizeForNewWindow() {
CWindow* candidate = g_pCompositor->m_pLastWindow; CWindow* candidate = g_pCompositor->m_pLastWindow;
if (!candidate) if (!candidate)
candidate = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace); candidate = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID);
// create a fake node // create a fake node
SDwindleNodeData node; SDwindleNodeData node;

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "IHyprLayout.hpp" #include "IHyprLayout.hpp"
#include "../desktop/DesktopTypes.hpp"
#include <list> #include <list>
#include <deque> #include <deque>
@@ -59,7 +60,7 @@ class CHyprDwindleLayout : public IHyprLayout {
virtual void alterSplitRatio(CWindow*, float, bool); virtual void alterSplitRatio(CWindow*, float, bool);
virtual std::string getLayoutName(); virtual std::string getLayoutName();
virtual void replaceWindowDataWith(CWindow* from, CWindow* to); virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
virtual Vector2D predictSizeForNewWindow(); virtual Vector2D predictSizeForNewWindowTiled();
virtual void onEnable(); virtual void onEnable();
virtual void onDisable(); virtual void onDisable();
@@ -78,6 +79,7 @@ class CHyprDwindleLayout : public IHyprLayout {
int getNodesOnWorkspace(const int&); int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false); void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
void calculateWorkspace(const PHLWORKSPACE& pWorkspace);
SDwindleNodeData* getNodeFromWindow(CWindow*); SDwindleNodeData* getNodeFromWindow(CWindow*);
SDwindleNodeData* getFirstNodeOnWorkspace(const int&); SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&); SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&);

View File

@@ -3,6 +3,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../desktop/Window.hpp"
void IHyprLayout::onWindowCreated(CWindow* pWindow, eDirection direction) { void IHyprLayout::onWindowCreated(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) { if (pWindow->m_bIsFloating) {
@@ -188,7 +189,7 @@ void IHyprLayout::onBeginDragWindow() {
g_pCompositor->setWindowFullscreen(DRAGGINGWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(DRAGGINGWINDOW, false, FULLSCREEN_FULL);
} }
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(DRAGGINGWINDOW->m_iWorkspaceID); const auto PWORKSPACE = DRAGGINGWINDOW->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && (!DRAGGINGWINDOW->m_bCreatedOverFullscreen || !DRAGGINGWINDOW->m_bIsFloating)) { if (PWORKSPACE->m_bHasFullscreenWindow && (!DRAGGINGWINDOW->m_bCreatedOverFullscreen || !DRAGGINGWINDOW->m_bIsFloating)) {
Debug::log(LOG, "Rejecting drag on a fullscreen workspace. (window under fullscreen)"); Debug::log(LOG, "Rejecting drag on a fullscreen workspace. (window under fullscreen)");
@@ -328,7 +329,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
static auto TIMER = std::chrono::high_resolution_clock::now(), MSTIMER = TIMER; static auto TIMER = std::chrono::high_resolution_clock::now(), MSTIMER = TIMER;
const auto SPECIAL = g_pCompositor->isWorkspaceSpecial(DRAGGINGWINDOW->m_iWorkspaceID); const auto SPECIAL = DRAGGINGWINDOW->onSpecialWorkspace();
const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y); const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y);
const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y); const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y);
@@ -355,7 +356,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
canSkipUpdate = std::clamp(MSMONITOR - TIMERDELTA, 0.0, MSMONITOR) > totalMs * 1.0 / m_iMouseMoveEventCount; canSkipUpdate = std::clamp(MSMONITOR - TIMERDELTA, 0.0, MSMONITOR) > totalMs * 1.0 / m_iMouseMoveEventCount;
} }
if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) || (TIMERDELTA < MSMONITOR && canSkipUpdate)) if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) || (TIMERDELTA < MSMONITOR && canSkipUpdate && g_pInputManager->dragMode != MBIND_MOVE))
return; return;
TIMER = std::chrono::high_resolution_clock::now(); TIMER = std::chrono::high_resolution_clock::now();
@@ -478,10 +479,10 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
if (!TILED) { if (!TILED) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f); const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID; pWindow->m_iMonitorID = PNEWMON->ID;
pWindow->moveToWorkspace(PNEWMON->specialWorkspaceID != 0 ? PNEWMON->specialWorkspaceID : PNEWMON->activeWorkspace); pWindow->moveToWorkspace(PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace);
pWindow->updateGroupOutputs(); pWindow->updateGroupOutputs();
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNEWMON->specialWorkspaceID != 0 ? PNEWMON->specialWorkspaceID : PNEWMON->activeWorkspace); const auto PWORKSPACE = PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow) if (PWORKSPACE->m_bHasFullscreenWindow)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false); g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false);
@@ -552,6 +553,8 @@ void IHyprLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) {
return; return;
} }
PWINDOW->setAnimationsToMove();
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + delta; PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + delta;
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
@@ -566,17 +569,17 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
if (!pWindow) if (!pWindow)
return nullptr; return nullptr;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = pWindow->m_pWorkspace;
// first of all, if this is a fullscreen workspace, // first of all, if this is a fullscreen workspace,
if (PWORKSPACE->m_bHasFullscreenWindow) if (PWORKSPACE->m_bHasFullscreenWindow)
return g_pCompositor->getFullscreenWindowOnWorkspace(pWindow->m_iWorkspaceID); return g_pCompositor->getFullscreenWindowOnWorkspace(pWindow->workspaceID());
if (pWindow->m_bIsFloating) { if (pWindow->m_bIsFloating) {
// find whether there is a floating window below this one // find whether there is a floating window below this one
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus && if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w.get() != pWindow) { !w->m_sAdditionalConfigData.noFocus && w.get() != pWindow) {
if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x,
w->m_vPosition.y + w->m_vSize.y)) { w->m_vPosition.y + w->m_vSize.y)) {
@@ -586,7 +589,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
} }
// let's try the last tiled window. // let's try the last tiled window.
if (m_pLastTiledWindow && m_pLastTiledWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID) if (m_pLastTiledWindow && m_pLastTiledWindow->m_pWorkspace == pWindow->m_pWorkspace)
return m_pLastTiledWindow; return m_pLastTiledWindow;
// if we don't, let's try to find any window that is in the middle // if we don't, let's try to find any window that is in the middle
@@ -596,7 +599,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
// if not, floating window // if not, floating window
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && !w->m_bX11ShouldntFocus && if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w.get() != pWindow) !w->m_sAdditionalConfigData.noFocus && w.get() != pWindow)
return w.get(); return w.get();
} }
@@ -609,10 +612,10 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
auto pWindowCandidate = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); auto pWindowCandidate = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!pWindowCandidate) if (!pWindowCandidate)
pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->m_iWorkspaceID); pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->workspaceID());
if (!pWindowCandidate) if (!pWindowCandidate)
pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->m_iWorkspaceID); pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID());
if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus || if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus ||
pWindowCandidate->m_iX11Type == 2 || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) pWindowCandidate->m_iX11Type == 2 || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)
@@ -641,8 +644,61 @@ void IHyprLayout::requestFocusForWindow(CWindow* pWindow) {
g_pCompositor->warpCursorTo(pWindow->middle()); g_pCompositor->warpCursorTo(pWindow->middle());
} }
Vector2D IHyprLayout::predictSizeForNewWindow() { Vector2D IHyprLayout::predictSizeForNewWindowFloating(CWindow* pWindow) { // get all rules, see if we have any size overrides.
return Vector2D{}; Vector2D sizeOverride = {};
if (g_pCompositor->m_pLastMonitor) {
for (auto& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) {
if (r.szRule.starts_with("size")) {
try {
const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1);
const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' '));
const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1);
const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow);
const auto SIZEX = SIZEXSTR == "max" ?
std::clamp(MAXSIZE.x, 20.0, g_pCompositor->m_pLastMonitor->vecSize.x) :
(!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * g_pCompositor->m_pLastMonitor->vecSize.x);
const auto SIZEY = SIZEYSTR == "max" ?
std::clamp(MAXSIZE.y, 20.0, g_pCompositor->m_pLastMonitor->vecSize.y) :
(!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * g_pCompositor->m_pLastMonitor->vecSize.y);
sizeOverride = {SIZEX, SIZEY};
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
break;
}
}
}
return sizeOverride;
}
Vector2D IHyprLayout::predictSizeForNewWindow(CWindow* pWindow) {
bool shouldBeFloated = g_pXWaylandManager->shouldBeFloated(pWindow, true);
if (!shouldBeFloated) {
for (auto& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) {
if (r.szRule.starts_with("float")) {
shouldBeFloated = true;
break;
}
}
}
Vector2D sizePredicted = {};
if (!shouldBeFloated)
sizePredicted = predictSizeForNewWindowTiled();
else
sizePredicted = predictSizeForNewWindowFloating(pWindow);
Vector2D maxSize = Vector2D{pWindow->m_uSurface.xdg->toplevel->pending.max_width, pWindow->m_uSurface.xdg->toplevel->pending.max_height};
if ((maxSize.x > 0 && maxSize.x < sizePredicted.x) || (maxSize.y > 0 && maxSize.y < sizePredicted.y))
sizePredicted = {};
return sizePredicted;
} }
IHyprLayout::~IHyprLayout() {} IHyprLayout::~IHyprLayout() {}

View File

@@ -1,9 +1,11 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../defines.hpp"
#include "../Window.hpp"
#include <any> #include <any>
class CWindow;
class CGradientValueData;
struct SWindowRenderLayoutHints { struct SWindowRenderLayoutHints {
bool isBorderGradient = false; bool isBorderGradient = false;
CGradientValueData* borderGradient; CGradientValueData* borderGradient;
@@ -185,7 +187,13 @@ class IHyprLayout {
Called to predict the size of a newly opened window to send it a configure. Called to predict the size of a newly opened window to send it a configure.
Return 0,0 if unpredictable Return 0,0 if unpredictable
*/ */
virtual Vector2D predictSizeForNewWindow(); virtual Vector2D predictSizeForNewWindowTiled() = 0;
/*
Prefer not overriding, use predictSizeForNewWindowTiled.
*/
virtual Vector2D predictSizeForNewWindow(CWindow* pWindow);
virtual Vector2D predictSizeForNewWindowFloating(CWindow* pWindow);
private: private:
int m_iMouseMoveEventCount; int m_iMouseMoveEventCount;

View File

@@ -44,23 +44,17 @@ SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) {
const auto PWORKSPACEDATA = &m_lMasterWorkspacesData.emplace_back(); const auto PWORKSPACEDATA = &m_lMasterWorkspacesData.emplace_back();
PWORKSPACEDATA->workspaceID = ws; PWORKSPACEDATA->workspaceID = ws;
static auto PORIENTATION = CConfigValue<std::string>("master:orientation"); static auto PORIENTATION = CConfigValue<std::string>("master:orientation");
const auto layoutoptsForWs = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(ws)).layoutopts;
std::string orientationForWs = *PORIENTATION;
if (layoutoptsForWs.contains("orientation")) if (*PORIENTATION == "top")
orientationForWs = layoutoptsForWs.at("orientation");
if (orientationForWs == "top") {
PWORKSPACEDATA->orientation = ORIENTATION_TOP; PWORKSPACEDATA->orientation = ORIENTATION_TOP;
} else if (orientationForWs == "right") { else if (*PORIENTATION == "right")
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT; PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
} else if (orientationForWs == "bottom") { else if (*PORIENTATION == "bottom")
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM; PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
} else if (orientationForWs == "center") { else if (*PORIENTATION == "center")
PWORKSPACEDATA->orientation = ORIENTATION_CENTER; PWORKSPACEDATA->orientation = ORIENTATION_CENTER;
} else { else
PWORKSPACEDATA->orientation = ORIENTATION_LEFT; PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
}
return PWORKSPACEDATA; return PWORKSPACEDATA;
} }
@@ -88,7 +82,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back(); const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back();
PNODE->workspaceID = pWindow->m_iWorkspaceID; PNODE->workspaceID = pWindow->workspaceID();
PNODE->pWindow = pWindow; PNODE->pWindow = pWindow;
static auto PNEWISMASTER = CConfigValue<Hyprlang::INT>("master:new_is_master"); static auto PNEWISMASTER = CConfigValue<Hyprlang::INT>("master:new_is_master");
@@ -97,9 +91,9 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
static auto PMFACT = CConfigValue<Hyprlang::FLOAT>("master:mfact"); static auto PMFACT = CConfigValue<Hyprlang::FLOAT>("master:mfact");
float lastSplitPercent = *PMFACT; float lastSplitPercent = *PMFACT;
auto OPENINGON = isWindowTiled(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID ? auto OPENINGON = isWindowTiled(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ?
getNodeFromWindow(g_pCompositor->m_pLastWindow) : getNodeFromWindow(g_pCompositor->m_pLastWindow) :
getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID); getMasterNodeOnWorkspace(pWindow->workspaceID());
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
@@ -131,8 +125,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
pWindow->applyGroupRules(); pWindow->applyGroupRules();
static auto PDROPATCURSOR = CConfigValue<Hyprlang::INT>("master:drop_at_cursor"); static auto PDROPATCURSOR = CConfigValue<Hyprlang::INT>("master:drop_at_cursor");
const auto PWORKSPACEDATA = getMasterWorkspaceData(pWindow->m_iWorkspaceID); eOrientation orientation = getDynamicOrientation(pWindow->m_pWorkspace);
eOrientation orientation = PWORKSPACEDATA->orientation;
const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE); const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE);
bool forceDropAsMaster = false; bool forceDropAsMaster = false;
@@ -140,7 +133,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
if (*PDROPATCURSOR && g_pInputManager->dragMode == MBIND_MOVE) { if (*PDROPATCURSOR && g_pInputManager->dragMode == MBIND_MOVE) {
if (WINDOWSONWORKSPACE > 2) { if (WINDOWSONWORKSPACE > 2) {
for (auto it = m_lMasterNodesData.begin(); it != m_lMasterNodesData.end(); ++it) { for (auto it = m_lMasterNodesData.begin(); it != m_lMasterNodesData.end(); ++it) {
if (it->workspaceID != pWindow->m_iWorkspaceID) if (it->workspaceID != pWindow->workspaceID())
continue; continue;
const CBox box = it->pWindow->getWindowIdealBoundingBoxIgnoreReserved(); const CBox box = it->pWindow->getWindowIdealBoundingBoxIgnoreReserved();
if (box.containsPoint(MOUSECOORDS)) { if (box.containsPoint(MOUSECOORDS)) {
@@ -284,88 +277,59 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
void CHyprMasterLayout::recalculateMonitor(const int& monid) { void CHyprMasterLayout::recalculateMonitor(const int& monid) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
if (!PMONITOR) if (!PMONITOR || !PMONITOR->activeWorkspace)
return;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
if (!PWORKSPACE)
return; return;
g_pHyprRenderer->damageMonitor(PMONITOR); g_pHyprRenderer->damageMonitor(PMONITOR);
if (PMONITOR->specialWorkspaceID) { if (PMONITOR->activeSpecialWorkspace)
const auto PSPECIALWS = g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID); calculateWorkspace(PMONITOR->activeSpecialWorkspace);
if (PSPECIALWS->m_bHasFullscreenWindow) { calculateWorkspace(PMONITOR->activeWorkspace);
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PSPECIALWS->m_iID); }
if (PSPECIALWS->m_efFullscreenMode == FULLSCREEN_FULL) { void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
if (!PMONITOR)
return;
if (pWorkspace->m_bHasFullscreenWindow) {
// massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID);
if (pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) {
PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; PFULLWINDOW->m_vRealSize = PMONITOR->vecSize;
} else if (PSPECIALWS->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { } else if (pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
SMasterNodeData fakeNode; SMasterNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW; fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight; fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = PSPECIALWS->m_iID; fakeNode.workspaceID = pWorkspace->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.position; PFULLWINDOW->m_vPosition = fakeNode.position;
PFULLWINDOW->m_vSize = fakeNode.size; PFULLWINDOW->m_vSize = fakeNode.size;
fakeNode.ignoreFullscreenChecks = true; fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode); applyNodeDataToWindow(&fakeNode);
} }
}
calculateWorkspace(PMONITOR->specialWorkspaceID);
}
if (PWORKSPACE->m_bHasFullscreenWindow) {
// massive hack from the fullscreen func
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition;
PFULLWINDOW->m_vRealSize = PMONITOR->vecSize;
} else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
SMasterNodeData fakeNode;
fakeNode.pWindow = PFULLWINDOW;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = PWORKSPACE->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.position;
PFULLWINDOW->m_vSize = fakeNode.size;
applyNodeDataToWindow(&fakeNode);
}
// if has fullscreen, don't calculate the rest
return; return;
} }
// calc the WS const auto PMASTERNODE = getMasterNodeOnWorkspace(pWorkspace->m_iID);
calculateWorkspace(PWORKSPACE->m_iID);
}
void CHyprMasterLayout::calculateWorkspace(const int& ws) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(ws);
if (!PWORKSPACE)
return;
const auto PWORKSPACEDATA = getMasterWorkspaceData(ws);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
const auto PMASTERNODE = getMasterNodeOnWorkspace(PWORKSPACE->m_iID);
if (!PMASTERNODE) if (!PMASTERNODE)
return; return;
eOrientation orientation = PWORKSPACEDATA->orientation; eOrientation orientation = getDynamicOrientation(pWorkspace);
bool centerMasterWindow = false; bool centerMasterWindow = false;
static auto ALWAYSCENTER = CConfigValue<Hyprlang::INT>("master:always_center_master"); static auto ALWAYSCENTER = CConfigValue<Hyprlang::INT>("master:always_center_master");
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing"); static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing");
const auto MASTERS = getMastersOnWorkspace(PWORKSPACE->m_iID); const auto MASTERS = getMastersOnWorkspace(pWorkspace->m_iID);
const auto WINDOWS = getNodesOnWorkspace(PWORKSPACE->m_iID); const auto WINDOWS = getNodesOnWorkspace(pWorkspace->m_iID);
const auto STACKWINDOWS = WINDOWS - MASTERS; const auto STACKWINDOWS = WINDOWS - MASTERS;
const auto WSSIZE = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight; const auto WSSIZE = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
const auto WSPOS = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; const auto WSPOS = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
@@ -388,7 +352,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
// check the total width and height so that later // check the total width and height so that later
// if larger/smaller than screen size them down/up // if larger/smaller than screen size them down/up
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID == PWORKSPACE->m_iID) { if (nd.workspaceID == pWorkspace->m_iID) {
if (nd.isMaster) if (nd.isMaster)
masterAccumulatedSize += totalSize / MASTERS * nd.percSize; masterAccumulatedSize += totalSize / MASTERS * nd.percSize;
else else
@@ -405,7 +369,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
applyNodeDataToWindow(PMASTERNODE); applyNodeDataToWindow(PMASTERNODE);
return; return;
} else if (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) { } else if (orientation == ORIENTATION_TOP || orientation == ORIENTATION_BOTTOM) {
const float HEIGHT = WSSIZE.y * PMASTERNODE->percMaster; const float HEIGHT = STACKWINDOWS != 0 ? WSSIZE.y * PMASTERNODE->percMaster : WSSIZE.y;
float widthLeft = WSSIZE.x; float widthLeft = WSSIZE.x;
int mastersLeft = MASTERS; int mastersLeft = MASTERS;
float nextX = 0; float nextX = 0;
@@ -415,7 +379,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
nextY = WSSIZE.y - HEIGHT; nextY = WSSIZE.y - HEIGHT;
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || !nd.isMaster) if (nd.workspaceID != pWorkspace->m_iID || !nd.isMaster)
continue; continue;
float WIDTH = mastersLeft > 1 ? widthLeft / mastersLeft * nd.percSize : widthLeft; float WIDTH = mastersLeft > 1 ? widthLeft / mastersLeft * nd.percSize : widthLeft;
@@ -452,7 +416,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
} }
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || !nd.isMaster) if (nd.workspaceID != pWorkspace->m_iID || !nd.isMaster)
continue; continue;
float HEIGHT = mastersLeft > 1 ? heightLeft / mastersLeft * nd.percSize : heightLeft; float HEIGHT = mastersLeft > 1 ? heightLeft / mastersLeft * nd.percSize : heightLeft;
@@ -489,7 +453,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
nextY = PMASTERNODE->size.y; nextY = PMASTERNODE->size.y;
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster) if (nd.workspaceID != pWorkspace->m_iID || nd.isMaster)
continue; continue;
float WIDTH = slavesLeft > 1 ? widthLeft / slavesLeft * nd.percSize : widthLeft; float WIDTH = slavesLeft > 1 ? widthLeft / slavesLeft * nd.percSize : widthLeft;
@@ -519,7 +483,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
nextX = PMASTERNODE->size.x; nextX = PMASTERNODE->size.x;
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster) if (nd.workspaceID != pWorkspace->m_iID || nd.isMaster)
continue; continue;
float HEIGHT = slavesLeft > 1 ? heightLeft / slavesLeft * nd.percSize : heightLeft; float HEIGHT = slavesLeft > 1 ? heightLeft / slavesLeft * nd.percSize : heightLeft;
@@ -559,7 +523,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
float slaveAccumulatedHeightR = 0; float slaveAccumulatedHeightR = 0;
if (*PSMARTRESIZING) { if (*PSMARTRESIZING) {
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster) if (nd.workspaceID != pWorkspace->m_iID || nd.isMaster)
continue; continue;
if (onRight) { if (onRight) {
@@ -573,7 +537,7 @@ void CHyprMasterLayout::calculateWorkspace(const int& ws) {
} }
for (auto& nd : m_lMasterNodesData) { for (auto& nd : m_lMasterNodesData) {
if (nd.workspaceID != PWORKSPACE->m_iID || nd.isMaster) if (nd.workspaceID != pWorkspace->m_iID || nd.isMaster)
continue; continue;
if (onRight) { if (onRight) {
@@ -626,7 +590,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) {
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (m->specialWorkspaceID == pNode->workspaceID) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) {
PMONITOR = m.get(); PMONITOR = m.get();
break; break;
} }
@@ -649,7 +613,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
const auto PWINDOW = pNode->pWindow; const auto PWINDOW = pNode->pWindow;
// get specific gaps and rules for this workspace, // get specific gaps and rules for this workspace,
// if user specified them in config // if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)); const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(PWINDOW->m_pWorkspace);
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return; return;
@@ -674,9 +638,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->m_vSize = pNode->size; PWINDOW->m_vSize = pNode->size;
PWINDOW->m_vPosition = pNode->position; PWINDOW->m_vPosition = pNode->position;
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() &&
(getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 || (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
(PWINDOW->m_bIsFullscreen && g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) {
PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2); PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2);
PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true); PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true);
@@ -709,7 +672,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
calcPos = calcPos + RESERVED.topLeft; calcPos = calcPos + RESERVED.topLeft;
calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight); calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight);
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && !PWINDOW->m_bIsFullscreen) { if (PWINDOW->onSpecialWorkspace() && !PWINDOW->m_bIsFullscreen) {
static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("master:special_scale_factor"); static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("master:special_scale_factor");
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR}; CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
@@ -760,11 +723,10 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
} }
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PMONITOR->activeWorkspace);
static auto ALWAYSCENTER = CConfigValue<Hyprlang::INT>("master:always_center_master"); static auto ALWAYSCENTER = CConfigValue<Hyprlang::INT>("master:always_center_master");
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing"); static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing");
eOrientation orientation = PWORKSPACEDATA->orientation; eOrientation orientation = getDynamicOrientation(PWINDOW->m_pWorkspace);
bool centered = orientation == ORIENTATION_CENTER && (*ALWAYSCENTER == 1); bool centered = orientation == ORIENTATION_CENTER && (*ALWAYSCENTER == 1);
double delta = 0; double delta = 0;
@@ -781,7 +743,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
const auto WINDOWS = getNodesOnWorkspace(PNODE->workspaceID); const auto WINDOWS = getNodesOnWorkspace(PNODE->workspaceID);
const auto STACKWINDOWS = WINDOWS - MASTERS; const auto STACKWINDOWS = WINDOWS - MASTERS;
if (getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 && !centered) if (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 && !centered)
return; return;
m_bForceWarps = true; m_bForceWarps = true;
@@ -793,7 +755,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
case ORIENTATION_TOP: delta = pixResize.y / PMONITOR->vecSize.y; break; case ORIENTATION_TOP: delta = pixResize.y / PMONITOR->vecSize.y; break;
case ORIENTATION_CENTER: case ORIENTATION_CENTER:
delta = pixResize.x / PMONITOR->vecSize.x; delta = pixResize.x / PMONITOR->vecSize.x;
if (WINDOWS > 2) { if (WINDOWS > 2 || *ALWAYSCENTER) {
if (!NONE || !PNODE->isMaster) if (!NONE || !PNODE->isMaster)
delta *= 2; delta *= 2;
if ((!PNODE->isMaster && DISPLAYLEFT) || (PNODE->isMaster && LEFT && *PSMARTRESIZING)) if ((!PNODE->isMaster && DISPLAYLEFT) || (PNODE->isMaster && LEFT && *PSMARTRESIZING))
@@ -803,7 +765,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
default: UNREACHABLE(); default: UNREACHABLE();
} }
const auto workspaceIdForResizing = PMONITOR->specialWorkspaceID == 0 ? PMONITOR->activeWorkspace : PMONITOR->specialWorkspaceID; const auto workspaceIdForResizing = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID();
for (auto& n : m_lMasterNodesData) { for (auto& n : m_lMasterNodesData) {
if (n.isMaster && n.workspaceID == workspaceIdForResizing) if (n.isMaster && n.workspaceID == workspaceIdForResizing)
n.percMaster = std::clamp(n.percMaster + delta, 0.05, 0.95); n.percMaster = std::clamp(n.percMaster + delta, 0.05, 0.95);
@@ -896,7 +858,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
return; // ignore return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = pWindow->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && on) { if (PWORKSPACE->m_bHasFullscreenWindow && on) {
// if the window wants to be fullscreen but there already is one, // if the window wants to be fullscreen but there already is one,
@@ -952,7 +914,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
fakeNode.pWindow = pWindow; fakeNode.pWindow = pWindow;
fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight; fakeNode.size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
fakeNode.workspaceID = pWindow->m_iWorkspaceID; fakeNode.workspaceID = pWindow->workspaceID();
pWindow->m_vPosition = fakeNode.position; pWindow->m_vPosition = fakeNode.position;
pWindow->m_vSize = fakeNode.size; pWindow->m_vSize = fakeNode.size;
fakeNode.ignoreFullscreenChecks = true; fakeNode.ignoreFullscreenChecks = true;
@@ -993,10 +955,15 @@ void CHyprMasterLayout::moveWindowTo(CWindow* pWindow, const std::string& dir) {
const auto PWINDOW2 = g_pCompositor->getWindowInDirection(pWindow, dir[0]); const auto PWINDOW2 = g_pCompositor->getWindowInDirection(pWindow, dir[0]);
if (pWindow->m_iWorkspaceID != PWINDOW2->m_iWorkspaceID) { if (!PWINDOW2)
return;
pWindow->setAnimationsToMove();
if (pWindow->m_pWorkspace != PWINDOW2->m_pWorkspace) {
// if different monitors, send to monitor // if different monitors, send to monitor
onWindowRemovedTiling(pWindow); onWindowRemovedTiling(pWindow);
pWindow->moveToWorkspace(PWINDOW2->m_iWorkspaceID); pWindow->moveToWorkspace(PWINDOW2->m_pWorkspace);
pWindow->m_iMonitorID = PWINDOW2->m_iMonitorID; pWindow->m_iMonitorID = PWINDOW2->m_iMonitorID;
const auto pMonitor = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto pMonitor = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
g_pCompositor->setActiveMonitor(pMonitor); g_pCompositor->setActiveMonitor(pMonitor);
@@ -1018,13 +985,16 @@ void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
if (PNODE->workspaceID != PNODE2->workspaceID) { if (PNODE->workspaceID != PNODE2->workspaceID) {
std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID); std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID);
std::swap(pWindow2->m_iWorkspaceID, pWindow->m_iWorkspaceID); std::swap(pWindow2->m_pWorkspace, pWindow->m_pWorkspace);
} }
// massive hack: just swap window pointers, lol // massive hack: just swap window pointers, lol
PNODE->pWindow = pWindow2; PNODE->pWindow = pWindow2;
PNODE2->pWindow = pWindow; PNODE2->pWindow = pWindow;
pWindow->setAnimationsToMove();
pWindow2->setAnimationsToMove();
recalculateMonitor(pWindow->m_iMonitorID); recalculateMonitor(pWindow->m_iMonitorID);
if (PNODE2->workspaceID != PNODE->workspaceID) if (PNODE2->workspaceID != PNODE->workspaceID)
recalculateMonitor(pWindow2->m_iMonitorID); recalculateMonitor(pWindow2->m_iMonitorID);
@@ -1041,7 +1011,7 @@ void CHyprMasterLayout::alterSplitRatio(CWindow* pWindow, float ratio, bool exac
if (!PNODE) if (!PNODE)
return; return;
const auto PMASTER = getMasterNodeOnWorkspace(pWindow->m_iWorkspaceID); const auto PMASTER = getMasterNodeOnWorkspace(pWindow->workspaceID());
float newRatio = exact ? ratio : PMASTER->percMaster + ratio; float newRatio = exact ? ratio : PMASTER->percMaster + ratio;
PMASTER->percMaster = std::clamp(newRatio, 0.05f, 0.95f); PMASTER->percMaster = std::clamp(newRatio, 0.05f, 0.95f);
@@ -1077,7 +1047,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
return; return;
if (header.pWindow->m_bIsFullscreen) { if (header.pWindow->m_bIsFullscreen) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID); const auto PWORKSPACE = header.pWindow->m_pWorkspace;
const auto FSMODE = PWORKSPACE->m_efFullscreenMode; const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
static auto INHERITFULLSCREEN = CConfigValue<Hyprlang::INT>("master:inherit_fullscreen"); static auto INHERITFULLSCREEN = CConfigValue<Hyprlang::INT>("master:inherit_fullscreen");
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL);
@@ -1117,7 +1087,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (!isWindowTiled(PWINDOW)) if (!isWindowTiled(PWINDOW))
return 0; return 0;
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID); const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->workspaceID());
if (!PMASTER) if (!PMASTER)
return 0; return 0;
@@ -1155,7 +1125,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (!PWINDOW) if (!PWINDOW)
return 0; return 0;
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID); const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->workspaceID());
if (!PMASTER) if (!PMASTER)
return 0; return 0;
@@ -1232,8 +1202,8 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PNODE = getNodeFromWindow(header.pWindow); const auto PNODE = getNodeFromWindow(header.pWindow);
const auto WINDOWS = getNodesOnWorkspace(header.pWindow->m_iWorkspaceID); const auto WINDOWS = getNodesOnWorkspace(header.pWindow->workspaceID());
const auto MASTERS = getMastersOnWorkspace(header.pWindow->m_iWorkspaceID); const auto MASTERS = getMastersOnWorkspace(header.pWindow->workspaceID());
static auto SMALLSPLIT = CConfigValue<Hyprlang::INT>("master:allow_small_split"); static auto SMALLSPLIT = CConfigValue<Hyprlang::INT>("master:allow_small_split");
if (MASTERS + 2 > WINDOWS && *SMALLSPLIT == 0) if (MASTERS + 2 > WINDOWS && *SMALLSPLIT == 0)
@@ -1243,7 +1213,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (!PNODE || PNODE->isMaster) { if (!PNODE || PNODE->isMaster) {
// first non-master node // first non-master node
for (auto& n : m_lMasterNodesData) { for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == header.pWindow->m_iWorkspaceID && !n.isMaster) { if (n.workspaceID == header.pWindow->workspaceID() && !n.isMaster) {
n.isMaster = true; n.isMaster = true;
break; break;
} }
@@ -1264,8 +1234,8 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PNODE = getNodeFromWindow(header.pWindow); const auto PNODE = getNodeFromWindow(header.pWindow);
const auto WINDOWS = getNodesOnWorkspace(header.pWindow->m_iWorkspaceID); const auto WINDOWS = getNodesOnWorkspace(header.pWindow->workspaceID());
const auto MASTERS = getMastersOnWorkspace(header.pWindow->m_iWorkspaceID); const auto MASTERS = getMastersOnWorkspace(header.pWindow->workspaceID());
if (WINDOWS < 2 || MASTERS < 2) if (WINDOWS < 2 || MASTERS < 2)
return 0; return 0;
@@ -1275,7 +1245,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (!PNODE || !PNODE->isMaster) { if (!PNODE || !PNODE->isMaster) {
// first non-master node // first non-master node
for (auto& nd : m_lMasterNodesData | std::views::reverse) { for (auto& nd : m_lMasterNodesData | std::views::reverse) {
if (nd.workspaceID == header.pWindow->m_iWorkspaceID && nd.isMaster) { if (nd.workspaceID == header.pWindow->workspaceID() && nd.isMaster) {
nd.isMaster = false; nd.isMaster = false;
break; break;
} }
@@ -1293,7 +1263,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID); const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->workspaceID());
if (command == "orientationleft") if (command == "orientationleft")
PWORKSPACEDATA->orientation = ORIENTATION_LEFT; PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
@@ -1315,19 +1285,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
} else if (command == "orientationcycle") { } else if (command == "orientationcycle") {
runOrientationCycle(header, &vars, 1); runOrientationCycle(header, &vars, 1);
} else if (command == "mfact") { } else if (command == "mfact") {
if (vars.size() >= 2) { g_pKeybindManager->m_mDispatchers["splitratio"](vars[1] + " " + vars[2]);
float newMfact = 0;
try {
newMfact = std::stof(vars[1]);
} catch (std::exception& e) {
Debug::log(ERR, "Argument is invalid: {}", e.what());
return 0;
}
for (auto& nd : m_lMasterNodesData) {
if (nd.isMaster)
nd.percMaster = std::clamp(newMfact, 0.05f, 0.95f);
}
}
} else if (command == "rollnext") { } else if (command == "rollnext") {
const auto PWINDOW = header.pWindow; const auto PWINDOW = header.pWindow;
const auto PNODE = getNodeFromWindow(PWINDOW); const auto PNODE = getNodeFromWindow(PWINDOW);
@@ -1401,7 +1359,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID); const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->workspaceID());
int nextOrPrev = 0; int nextOrPrev = 0;
for (size_t i = 0; i < cycle.size(); ++i) { for (size_t i = 0; i < cycle.size(); ++i) {
@@ -1442,6 +1400,30 @@ void CHyprMasterLayout::buildOrientationCycleVectorFromVars(std::vector<eOrienta
} }
} }
eOrientation CHyprMasterLayout::getDynamicOrientation(PHLWORKSPACE pWorkspace) {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(pWorkspace);
std::string orientationString;
if (WORKSPACERULE.layoutopts.contains("orientation"))
orientationString = WORKSPACERULE.layoutopts.at("orientation");
eOrientation orientation = getMasterWorkspaceData(pWorkspace->m_iID)->orientation;
// override if workspace rule is set
if (!orientationString.empty()) {
if (orientationString == "top")
orientation = ORIENTATION_TOP;
else if (orientationString == "right")
orientation = ORIENTATION_RIGHT;
else if (orientationString == "bottom")
orientation = ORIENTATION_BOTTOM;
else if (orientationString == "center")
orientation = ORIENTATION_CENTER;
else
orientation = ORIENTATION_LEFT;
}
return orientation;
}
void CHyprMasterLayout::replaceWindowDataWith(CWindow* from, CWindow* to) { void CHyprMasterLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
const auto PNODE = getNodeFromWindow(from); const auto PNODE = getNodeFromWindow(from);
@@ -1453,25 +1435,25 @@ void CHyprMasterLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
applyNodeDataToWindow(PNODE); applyNodeDataToWindow(PNODE);
} }
Vector2D CHyprMasterLayout::predictSizeForNewWindow() { Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() {
static auto PNEWISMASTER = CConfigValue<Hyprlang::INT>("master:new_is_master"); static auto PNEWISMASTER = CConfigValue<Hyprlang::INT>("master:new_is_master");
if (!g_pCompositor->m_pLastMonitor) if (!g_pCompositor->m_pLastMonitor)
return {}; return {};
const int NODES = getNodesOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace); const int NODES = getNodesOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID);
if (NODES <= 0) if (NODES <= 0)
return g_pCompositor->m_pLastMonitor->vecSize; return g_pCompositor->m_pLastMonitor->vecSize;
const auto MASTER = getMasterNodeOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto MASTER = getMasterNodeOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID);
if (!MASTER) // wtf if (!MASTER) // wtf
return {}; return {};
if (*PNEWISMASTER) { if (*PNEWISMASTER) {
return MASTER->size; return MASTER->size;
} else { } else {
const auto SLAVES = NODES - getMastersOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto SLAVES = NODES - getMastersOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID);
// TODO: make this better // TODO: make this better
return {g_pCompositor->m_pLastMonitor->vecSize.x - MASTER->size.x, g_pCompositor->m_pLastMonitor->vecSize.y / (SLAVES + 1)}; return {g_pCompositor->m_pLastMonitor->vecSize.x - MASTER->size.x, g_pCompositor->m_pLastMonitor->vecSize.y / (SLAVES + 1)};

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "IHyprLayout.hpp" #include "IHyprLayout.hpp"
#include "../desktop/DesktopTypes.hpp"
#include "../config/ConfigManager.hpp" #include "../config/ConfigManager.hpp"
#include <vector> #include <vector>
#include <list> #include <list>
@@ -65,7 +66,7 @@ class CHyprMasterLayout : public IHyprLayout {
virtual void alterSplitRatio(CWindow*, float, bool); virtual void alterSplitRatio(CWindow*, float, bool);
virtual std::string getLayoutName(); virtual std::string getLayoutName();
virtual void replaceWindowDataWith(CWindow* from, CWindow* to); virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
virtual Vector2D predictSizeForNewWindow(); virtual Vector2D predictSizeForNewWindowTiled();
virtual void onEnable(); virtual void onEnable();
virtual void onDisable(); virtual void onDisable();
@@ -79,12 +80,13 @@ class CHyprMasterLayout : public IHyprLayout {
void buildOrientationCycleVectorFromVars(std::vector<eOrientation>& cycle, CVarList& vars); void buildOrientationCycleVectorFromVars(std::vector<eOrientation>& cycle, CVarList& vars);
void buildOrientationCycleVectorFromEOperation(std::vector<eOrientation>& cycle); void buildOrientationCycleVectorFromEOperation(std::vector<eOrientation>& cycle);
void runOrientationCycle(SLayoutMessageHeader& header, CVarList* vars, int next); void runOrientationCycle(SLayoutMessageHeader& header, CVarList* vars, int next);
eOrientation getDynamicOrientation(PHLWORKSPACE);
int getNodesOnWorkspace(const int&); int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SMasterNodeData*); void applyNodeDataToWindow(SMasterNodeData*);
SMasterNodeData* getNodeFromWindow(CWindow*); SMasterNodeData* getNodeFromWindow(CWindow*);
SMasterNodeData* getMasterNodeOnWorkspace(const int&); SMasterNodeData* getMasterNodeOnWorkspace(const int&);
SMasterWorkspaceData* getMasterWorkspaceData(const int&); SMasterWorkspaceData* getMasterWorkspaceData(const int&);
void calculateWorkspace(const int&); void calculateWorkspace(PHLWORKSPACE);
CWindow* getNextWindow(CWindow*, bool); CWindow* getNextWindow(CWindow*, bool);
int getMastersOnWorkspace(const int&); int getMastersOnWorkspace(const int&);

View File

@@ -6,7 +6,6 @@
#ifndef NDEBUG #ifndef NDEBUG
#ifdef HYPRLAND_DEBUG #ifdef HYPRLAND_DEBUG
#define HYPRLAND_DEBUG
#define ISDEBUG true #define ISDEBUG true
#else #else
#define ISDEBUG false #define ISDEBUG false

View File

@@ -3,8 +3,10 @@
#include "HookSystemManager.hpp" #include "HookSystemManager.hpp"
#include "macros.hpp" #include "macros.hpp"
#include "../config/ConfigValue.hpp" #include "../config/ConfigValue.hpp"
#include "../desktop/Window.hpp"
#include "eventLoop/EventLoopManager.hpp"
int wlTick(void* data) { int wlTick(std::shared_ptr<CEventLoopTimer> self, void* data) {
if (g_pAnimationManager) if (g_pAnimationManager)
g_pAnimationManager->onTicked(); g_pAnimationManager->onTicked();
@@ -24,8 +26,8 @@ CAnimationManager::CAnimationManager() {
std::vector<Vector2D> points = {Vector2D(0, 0.75f), Vector2D(0.15f, 1.f)}; std::vector<Vector2D> points = {Vector2D(0, 0.75f), Vector2D(0.15f, 1.f)};
m_mBezierCurves["default"].setup(&points); m_mBezierCurves["default"].setup(&points);
m_pAnimationTick = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, &wlTick, nullptr); m_pAnimationTimer = std::make_unique<CEventLoopTimer>(std::chrono::microseconds(500), wlTick, nullptr);
wl_event_source_timer_update(m_pAnimationTick, 1); g_pEventLoopManager->addTimer(m_pAnimationTimer);
} }
void CAnimationManager::removeAllBeziers() { void CAnimationManager::removeAllBeziers() {
@@ -79,14 +81,22 @@ void CAnimationManager::tick() {
// window stuff // window stuff
const auto PWINDOW = (CWindow*)av->m_pWindow; const auto PWINDOW = (CWindow*)av->m_pWindow;
const auto PWORKSPACE = (CWorkspace*)av->m_pWorkspace; PHLWORKSPACE PWORKSPACE = av->m_pWorkspace.lock();
const auto PLAYER = (SLayerSurface*)av->m_pLayer; const auto PLAYER = (SLayerSurface*)av->m_pLayer;
CMonitor* PMONITOR = nullptr; CMonitor* PMONITOR = nullptr;
bool animationsDisabled = animGlobalDisabled; bool animationsDisabled = animGlobalDisabled;
CBox WLRBOXPREV = {0, 0, 0, 0};
if (PWINDOW) { if (PWINDOW) {
WLRBOXPREV = PWINDOW->getFullWindowBoundingBox(); if (av->m_eDamagePolicy == AVARDAMAGE_ENTIRE) {
g_pHyprRenderer->damageWindow(PWINDOW);
} else if (av->m_eDamagePolicy == AVARDAMAGE_BORDER) {
const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER);
PDECO->damageEntire();
} else if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW) {
const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW);
PDECO->damageEntire();
}
PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (!PMONITOR) if (!PMONITOR)
continue; continue;
@@ -95,22 +105,49 @@ void CAnimationManager::tick() {
PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
if (!PMONITOR) if (!PMONITOR)
continue; continue;
WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y};
// dont damage the whole monitor on workspace change, unless it's a special workspace, because dim/blur etc
if (PWORKSPACE->m_bIsSpecialWorkspace)
g_pHyprRenderer->damageMonitor(PMONITOR);
// TODO: just make this into a damn callback already vax... // TODO: just make this into a damn callback already vax...
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!w->isHidden() && w->m_bIsMapped && w->m_bIsFloating) if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != PWORKSPACE)
continue;
if (w->m_bIsFloating && !w->m_bPinned) {
// still doing the full damage hack for floating because sometimes when the window
// goes through multiple monitors the last rendered frame is missing damage somehow??
const CBox windowBoxNoOffset = w->getFullWindowBoundingBox();
const CBox monitorBox = {PMONITOR->vecPosition, PMONITOR->vecSize};
if (windowBoxNoOffset.intersection(monitorBox) != windowBoxNoOffset) // on edges between multiple monitors
g_pHyprRenderer->damageWindow(w.get(), true);
}
if (PWORKSPACE->m_bIsSpecialWorkspace)
g_pHyprRenderer->damageWindow(w.get(), true); // hack for special too because it can cross multiple monitors
}
// damage any workspace window that is on any monitor
for (auto& w : g_pCompositor->m_vWindows) {
if (!g_pCompositor->windowValidMapped(w.get()) || w->m_pWorkspace != PWORKSPACE || w->m_bPinned)
continue;
g_pHyprRenderer->damageWindow(w.get()); g_pHyprRenderer->damageWindow(w.get());
} }
} else if (PLAYER) { } else if (PLAYER) {
WLRBOXPREV = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()}; // "some fucking layers miss 1 pixel???" -- vaxry
CBox expandBox = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()};
expandBox.expand(5);
g_pHyprRenderer->damageBox(&expandBox);
PMONITOR = g_pCompositor->getMonitorFromVector(Vector2D(PLAYER->geometry.x, PLAYER->geometry.y) + Vector2D(PLAYER->geometry.width, PLAYER->geometry.height) / 2.f); PMONITOR = g_pCompositor->getMonitorFromVector(Vector2D(PLAYER->geometry.x, PLAYER->geometry.y) + Vector2D(PLAYER->geometry.width, PLAYER->geometry.height) / 2.f);
if (!PMONITOR) if (!PMONITOR)
continue; continue;
animationsDisabled = animationsDisabled || PLAYER->noAnimations; animationsDisabled = animationsDisabled || PLAYER->noAnimations;
} }
const bool VISIBLE = PWINDOW ? g_pCompositor->isWorkspaceVisible(PWINDOW->m_iWorkspaceID) : true; const bool VISIBLE = PWINDOW && PWINDOW->m_pWorkspace ? g_pCompositor->isWorkspaceVisible(PWINDOW->m_pWorkspace) : true;
// beziers are with a switch unforto // beziers are with a switch unforto
// TODO: maybe do something cleaner // TODO: maybe do something cleaner
@@ -171,33 +208,26 @@ void CAnimationManager::tick() {
switch (av->m_eDamagePolicy) { switch (av->m_eDamagePolicy) {
case AVARDAMAGE_ENTIRE: { case AVARDAMAGE_ENTIRE: {
g_pHyprRenderer->damageBox(&WLRBOXPREV);
if (PWINDOW) { if (PWINDOW) {
PWINDOW->updateWindowDecos(); PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
} else if (PWORKSPACE) { } else if (PWORKSPACE) {
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->isHidden()) if (!g_pCompositor->windowValidMapped(w.get()) || w->m_pWorkspace != PWORKSPACE)
continue;
if (w->m_iWorkspaceID != PWORKSPACE->m_iID)
continue; continue;
w->updateWindowDecos(); w->updateWindowDecos();
if (w->m_bIsFloating) { // damage any workspace window that is on any monitor
auto bb = w->getFullWindowBoundingBox(); if (!w->m_bPinned)
bb.translate(PWORKSPACE->m_vRenderOffset.value()); g_pHyprRenderer->damageWindow(w.get());
g_pHyprRenderer->damageBox(&bb);
}
} }
} else if (PLAYER) { } else if (PLAYER) {
if (PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) if (PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR);
// some fucking layers miss 1 pixel??? // some fucking layers miss 1 pixel???
CBox expandBox = WLRBOXPREV; CBox expandBox = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()};
expandBox.expand(5); expandBox.expand(5);
g_pHyprRenderer->damageBox(&expandBox); g_pHyprRenderer->damageBox(&expandBox);
} }
@@ -206,28 +236,8 @@ void CAnimationManager::tick() {
case AVARDAMAGE_BORDER: { case AVARDAMAGE_BORDER: {
RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!"); RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!");
// TODO: move this to the border class const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER);
PDECO->damageEntire();
// damage only the border.
const auto ROUNDING = PWINDOW->rounding();
const auto ROUNDINGSIZE = ROUNDING + 1;
const auto BORDERSIZE = PWINDOW->getRealBorderSize();
// damage for old box
g_pHyprRenderer->damageBox(WLRBOXPREV.x - BORDERSIZE, WLRBOXPREV.y - BORDERSIZE, WLRBOXPREV.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // top
g_pHyprRenderer->damageBox(WLRBOXPREV.x - BORDERSIZE, WLRBOXPREV.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, WLRBOXPREV.height + 2 * BORDERSIZE); // left
g_pHyprRenderer->damageBox(WLRBOXPREV.x + WLRBOXPREV.width - ROUNDINGSIZE, WLRBOXPREV.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE,
WLRBOXPREV.height + 2 * BORDERSIZE); // right
g_pHyprRenderer->damageBox(WLRBOXPREV.x, WLRBOXPREV.y + WLRBOXPREV.height - ROUNDINGSIZE, WLRBOXPREV.width + 2 * BORDERSIZE,
BORDERSIZE + ROUNDINGSIZE); // bottom
// damage for new box
const CBox WLRBOXNEW = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y};
g_pHyprRenderer->damageBox(WLRBOXNEW.x - BORDERSIZE, WLRBOXNEW.y - BORDERSIZE, WLRBOXNEW.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // top
g_pHyprRenderer->damageBox(WLRBOXNEW.x - BORDERSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE, WLRBOXNEW.height + 2 * BORDERSIZE); // left
g_pHyprRenderer->damageBox(WLRBOXNEW.x + WLRBOXNEW.width - ROUNDINGSIZE, WLRBOXNEW.y - BORDERSIZE, BORDERSIZE + ROUNDINGSIZE,
WLRBOXNEW.height + 2 * BORDERSIZE); // right
g_pHyprRenderer->damageBox(WLRBOXNEW.x, WLRBOXNEW.y + WLRBOXNEW.height - ROUNDINGSIZE, WLRBOXNEW.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // bottom
break; break;
} }
@@ -536,7 +546,7 @@ void CAnimationManager::scheduleTick() {
const auto PMOSTHZ = g_pHyprRenderer->m_pMostHzMonitor; const auto PMOSTHZ = g_pHyprRenderer->m_pMostHzMonitor;
if (!PMOSTHZ) { if (!PMOSTHZ) {
wl_event_source_timer_update(m_pAnimationTick, 16); m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(16));
return; return;
} }
@@ -546,5 +556,5 @@ void CAnimationManager::scheduleTick() {
const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it
wl_event_source_timer_update(m_pAnimationTick, std::floor(TOPRES)); m_pAnimationTimer->updateTimeout(std::chrono::milliseconds((int)std::floor(TOPRES)));
} }

View File

@@ -5,8 +5,10 @@
#include <unordered_map> #include <unordered_map>
#include "../helpers/AnimatedVariable.hpp" #include "../helpers/AnimatedVariable.hpp"
#include "../helpers/BezierCurve.hpp" #include "../helpers/BezierCurve.hpp"
#include "../Window.hpp"
#include "../helpers/Timer.hpp" #include "../helpers/Timer.hpp"
#include "eventLoop/EventLoopTimer.hpp"
class CWindow;
class CAnimationManager { class CAnimationManager {
public: public:
@@ -31,7 +33,7 @@ class CAnimationManager {
std::vector<CBaseAnimatedVariable*> m_vAnimatedVariables; std::vector<CBaseAnimatedVariable*> m_vAnimatedVariables;
std::vector<CBaseAnimatedVariable*> m_vActiveAnimatedVariables; std::vector<CBaseAnimatedVariable*> m_vActiveAnimatedVariables;
wl_event_source* m_pAnimationTick; std::shared_ptr<CEventLoopTimer> m_pAnimationTimer;
float m_fLastTickTime; // in ms float m_fLastTickTime; // in ms

View File

@@ -12,8 +12,18 @@ static int cursorAnimTimer(void* data) {
return 1; return 1;
} }
static void hcLogger(enum eHyprcursorLogLevel level, char* message) {
if (level == HC_LOG_TRACE)
return;
Debug::log(NONE, "[hc] {}", message);
}
CCursorManager::CCursorManager() { CCursorManager::CCursorManager() {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.empty() ? nullptr : m_szTheme.c_str()); m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger);
if (!m_pHyprcursor->valid())
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", m_szTheme);
// find default size. First, HYPRCURSOR_SIZE, then XCURSOR_SIZE, then 24 // find default size. First, HYPRCURSOR_SIZE, then XCURSOR_SIZE, then 24
auto SIZE = getenv("HYPRCURSOR_SIZE"); auto SIZE = getenv("HYPRCURSOR_SIZE");
@@ -119,6 +129,7 @@ void CCursorManager::setCursorFromName(const std::string& name) {
if (m_sCurrentCursorShapeData.images.size() < 1) { if (m_sCurrentCursorShapeData.images.size() < 1) {
Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName"); Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName");
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, m_pWLRXCursorMgr, name.c_str());
return; return;
} }
} }
@@ -128,8 +139,8 @@ void CCursorManager::setCursorFromName(const std::string& name) {
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
if (g_pCompositor->m_sWLRCursor) { if (g_pCompositor->m_sWLRCursor) {
wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY, wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[0].hotspotX / m_fCursorScale,
m_fCursorScale); m_sCurrentCursorShapeData.images[0].hotspotY / m_fCursorScale, m_fCursorScale);
if (m_vCursorBuffers.size() > 1) if (m_vCursorBuffers.size() > 1)
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
} }
@@ -160,8 +171,8 @@ void CCursorManager::tickAnimatedCursor() {
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY})); Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}));
if (g_pCompositor->m_sWLRCursor) if (g_pCompositor->m_sWLRCursor)
wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX / m_fCursorScale,
m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY, m_fCursorScale); m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY / m_fCursorScale, m_fCursorScale);
wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay); wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay);
} }
@@ -220,12 +231,12 @@ void CCursorManager::updateTheme() {
} }
void CCursorManager::changeTheme(const std::string& name, const int size) { void CCursorManager::changeTheme(const std::string& name, const int size) {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(name.empty() ? "" : name.c_str()); m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(name.empty() ? "" : name.c_str(), hcLogger);
m_szTheme = name; m_szTheme = name;
m_iSize = size; m_iSize = size;
setenv("XCURSOR_SIZE", std::to_string(m_iSize).c_str(), true); if (!m_pHyprcursor->valid())
setenv("XCURSOR_THEME", name.c_str(), true); Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", m_szTheme);
updateTheme(); updateTheme();
} }

View File

@@ -55,7 +55,7 @@ class CCursorManager {
std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor; std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor;
std::string m_szTheme = ""; std::string m_szTheme = "";
int m_iSize = 24; int m_iSize = 0;
float m_fCursorScale = 1.0; float m_fCursorScale = 1.0;
Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo; Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo;

View File

@@ -15,6 +15,7 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <string> #include <string>
#include <algorithm>
CEventManager::CEventManager() {} CEventManager::CEventManager() {}
@@ -139,7 +140,9 @@ void CEventManager::postEvent(const SHyprIPCEvent event) {
} }
std::thread( std::thread(
[&](const SHyprIPCEvent ev) { [this](SHyprIPCEvent ev) {
std::replace(ev.data.begin(), ev.data.end(), '\n', ' ');
eventQueueMutex.lock(); eventQueueMutex.lock();
m_dQueuedEvents.push_back(ev); m_dQueuedEvents.push_back(ev);
eventQueueMutex.unlock(); eventQueueMutex.unlock();

View File

@@ -25,6 +25,8 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["killactive"] = killActive; m_mDispatchers["killactive"] = killActive;
m_mDispatchers["closewindow"] = kill; m_mDispatchers["closewindow"] = kill;
m_mDispatchers["togglefloating"] = toggleActiveFloating; m_mDispatchers["togglefloating"] = toggleActiveFloating;
m_mDispatchers["setfloating"] = setActiveFloating;
m_mDispatchers["settiled"] = setActiveTiled;
m_mDispatchers["workspace"] = changeworkspace; m_mDispatchers["workspace"] = changeworkspace;
m_mDispatchers["renameworkspace"] = renameWorkspace; m_mDispatchers["renameworkspace"] = renameWorkspace;
m_mDispatchers["fullscreen"] = fullscreenActive; m_mDispatchers["fullscreen"] = fullscreenActive;
@@ -200,11 +202,17 @@ bool CKeybindManager::ensureMouseBindState() {
return false; return false;
if (g_pInputManager->currentlyDraggedWindow) { if (g_pInputManager->currentlyDraggedWindow) {
CWindow* lastDraggedWindow = g_pInputManager->currentlyDraggedWindow;
m_bIsMouseBindActive = false; m_bIsMouseBindActive = false;
g_pLayoutManager->getCurrentLayout()->onEndDragWindow(); g_pLayoutManager->getCurrentLayout()->onEndDragWindow();
g_pInputManager->currentlyDraggedWindow = nullptr; g_pInputManager->currentlyDraggedWindow = nullptr;
g_pInputManager->dragMode = MBIND_INVALID; g_pInputManager->dragMode = MBIND_INVALID;
g_pCompositor->updateWorkspaceWindows(lastDraggedWindow->workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(lastDraggedWindow->workspaceID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
return true; return true;
} }
@@ -223,13 +231,13 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
return false; return false;
} }
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
const auto PNEWMAINWORKSPACE = g_pCompositor->getWorkspaceByID(monitor->activeWorkspace); const auto PNEWMAINWORKSPACE = monitor->activeWorkspace;
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
PNEWMAINWORKSPACE->rememberPrevWorkspace(PWORKSPACE); PNEWMAINWORKSPACE->rememberPrevWorkspace(PWORKSPACE);
const auto PNEWWORKSPACE = monitor->specialWorkspaceID != 0 ? g_pCompositor->getWorkspaceByID(monitor->specialWorkspaceID) : PNEWMAINWORKSPACE; const auto PNEWWORKSPACE = monitor->activeSpecialWorkspace ? monitor->activeSpecialWorkspace : PNEWMAINWORKSPACE;
const auto PNEWWINDOW = PNEWWORKSPACE->getLastFocusedWindow(); const auto PNEWWINDOW = PNEWWORKSPACE->getLastFocusedWindow();
if (PNEWWINDOW) { if (PNEWWINDOW) {
@@ -257,8 +265,8 @@ void CKeybindManager::switchToWindow(CWindow* PWINDOWTOCHANGETO) {
// remove constraints // remove constraints
g_pInputManager->unconstrainMouse(); g_pInputManager->unconstrainMouse();
if (PLASTWINDOW && PLASTWINDOW->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && PLASTWINDOW->m_bIsFullscreen) { if (PLASTWINDOW && PLASTWINDOW->m_pWorkspace == PWINDOWTOCHANGETO->m_pWorkspace && PLASTWINDOW->m_bIsFullscreen) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PLASTWINDOW->m_iWorkspaceID); const auto PWORKSPACE = PLASTWINDOW->m_pWorkspace;
const auto FSMODE = PWORKSPACE->m_efFullscreenMode; const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
if (!PWINDOWTOCHANGETO->m_bPinned) if (!PWINDOWTOCHANGETO->m_bPinned)
@@ -499,7 +507,9 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
if (g_pCompositor->m_sSeat.exclusiveClient) if (g_pCompositor->m_sSeat.exclusiveClient)
Debug::log(LOG, "Keybind handling only locked (inhibitor)"); Debug::log(LOG, "Keybind handling only locked (inhibitor)");
if (!m_lShortcutInhibitors.empty()) { static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
if (!*PDISABLEINHIBIT && !m_lShortcutInhibitors.empty()) {
for (auto& i : m_lShortcutInhibitors) { for (auto& i : m_lShortcutInhibitors) {
if (i.pWlrInhibitor->surface == g_pCompositor->m_pLastFocus) { if (i.pWlrInhibitor->surface == g_pCompositor->m_pLastFocus) {
Debug::log(LOG, "Keybind handling is disabled due to an inhibitor for surface {:x}", (uintptr_t)i.pWlrInhibitor->surface); Debug::log(LOG, "Keybind handling is disabled due to an inhibitor for surface {:x}", (uintptr_t)i.pWlrInhibitor->surface);
@@ -827,7 +837,7 @@ void CKeybindManager::clearKeybinds() {
m_lKeybinds.clear(); m_lKeybinds.clear();
} }
void CKeybindManager::toggleActiveFloating(std::string args) { static void toggleActiveFloatingCore(std::string args, std::optional<bool> floatState) {
CWindow* PWINDOW = nullptr; CWindow* PWINDOW = nullptr;
if (args != "active" && args.length() > 1) if (args != "active" && args.length() > 1)
@@ -838,29 +848,43 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
if (!PWINDOW) if (!PWINDOW)
return; return;
if (floatState.has_value() && floatState == PWINDOW->m_bIsFloating)
return;
// remove drag status // remove drag status
g_pInputManager->currentlyDraggedWindow = nullptr; g_pInputManager->currentlyDraggedWindow = nullptr;
if (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->m_sGroupData.pNextWindow != PWINDOW) { if (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->m_sGroupData.pNextWindow != PWINDOW) {
const auto PCURRENT = PWINDOW->getGroupCurrent(); const auto PCURRENT = PWINDOW->getGroupCurrent();
PCURRENT->m_bIsFloating = !PCURRENT->m_bIsFloating; PCURRENT->m_bIsFloating = !PCURRENT->m_bIsFloating;
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PCURRENT); g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PCURRENT);
CWindow* curr = PCURRENT->m_sGroupData.pNextWindow; CWindow* curr = PCURRENT->m_sGroupData.pNextWindow;
while (curr != PCURRENT) { while (curr != PCURRENT) {
curr->m_bIsFloating = PCURRENT->m_bIsFloating; curr->m_bIsFloating = PCURRENT->m_bIsFloating;
curr->updateDynamicRules();
curr->updateSpecialRenderData();
curr = curr->m_sGroupData.pNextWindow; curr = curr->m_sGroupData.pNextWindow;
} }
} else { } else {
PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating; PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating;
PWINDOW->updateDynamicRules();
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW); g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW);
} }
g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID());
g_pCompositor->updateWorkspaceSpecialRenderData(PWINDOW->workspaceID());
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
}
void CKeybindManager::toggleActiveFloating(std::string args) {
return toggleActiveFloatingCore(args, std::nullopt);
}
void CKeybindManager::setActiveFloating(std::string args) {
return toggleActiveFloatingCore(args, true);
}
void CKeybindManager::setActiveTiled(std::string args) {
return toggleActiveFloatingCore(args, false);
} }
void CKeybindManager::centerWindow(std::string args) { void CKeybindManager::centerWindow(std::string args) {
@@ -906,7 +930,7 @@ void CKeybindManager::changeworkspace(std::string args) {
if (!PMONITOR) if (!PMONITOR)
return; return;
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto PCURRENTWORKSPACE = PMONITOR->activeWorkspace;
const bool EXPLICITPREVIOUS = args.starts_with("previous"); const bool EXPLICITPREVIOUS = args.starts_with("previous");
if (args.starts_with("previous")) { if (args.starts_with("previous")) {
@@ -975,7 +999,7 @@ void CKeybindManager::changeworkspace(std::string args) {
if (BISWORKSPACECURRENT) { if (BISWORKSPACECURRENT) {
if (*PALLOWWORKSPACECYCLES) if (*PALLOWWORKSPACECYCLES)
pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE);
else if (!EXPLICITPREVIOUS) else if (!EXPLICITPREVIOUS && !*PBACKANDFORTH)
pWorkspaceToChangeTo->rememberPrevWorkspace(nullptr); pWorkspaceToChangeTo->rememberPrevWorkspace(nullptr);
} else } else
pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE);
@@ -1023,14 +1047,14 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
return; return;
} }
if (WORKSPACEID == PWINDOW->m_iWorkspaceID) { if (WORKSPACEID == PWINDOW->workspaceID()) {
Debug::log(LOG, "Not moving to workspace because it didn't change."); Debug::log(LOG, "Not moving to workspace because it didn't change.");
return; return;
} }
auto pWorkspace = g_pCompositor->getWorkspaceByID(WORKSPACEID); auto pWorkspace = g_pCompositor->getWorkspaceByID(WORKSPACEID);
CMonitor* pMonitor = nullptr; CMonitor* pMonitor = nullptr;
const auto POLDWS = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); const auto POLDWS = PWINDOW->m_pWorkspace;
static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles"); static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
@@ -1085,7 +1109,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
return; return;
} }
if (WORKSPACEID == PWINDOW->m_iWorkspaceID) if (WORKSPACEID == PWINDOW->workspaceID())
return; return;
g_pHyprRenderer->damageWindow(PWINDOW); g_pHyprRenderer->damageWindow(PWINDOW);
@@ -1199,7 +1223,7 @@ void CKeybindManager::moveActiveTo(std::string args) {
if (!PNEWMONITOR) if (!PNEWMONITOR)
return; return;
moveActiveToWorkspace(std::to_string(PNEWMONITOR->activeWorkspace)); moveActiveToWorkspace(PNEWMONITOR->activeWorkspace->getConfigName());
return; return;
} }
@@ -1244,7 +1268,7 @@ void CKeybindManager::moveActiveTo(std::string args) {
if (!PMONITORTOCHANGETO) if (!PMONITORTOCHANGETO)
return; return;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITORTOCHANGETO->activeWorkspace); const auto PWORKSPACE = PMONITORTOCHANGETO->activeWorkspace;
moveActiveToWorkspace(PWORKSPACE->getConfigName()); moveActiveToWorkspace(PWORKSPACE->getConfigName());
} }
@@ -1261,8 +1285,6 @@ void CKeybindManager::toggleGroup(std::string args) {
PWINDOW->createGroup(); PWINDOW->createGroup();
else else
PWINDOW->destroyGroup(); PWINDOW->destroyGroup();
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
} }
void CKeybindManager::changeGroupActive(std::string args) { void CKeybindManager::changeGroupActive(std::string args) {
@@ -1303,7 +1325,7 @@ void CKeybindManager::toggleSplit(std::string args) {
if (!header.pWindow) if (!header.pWindow)
return; return;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID); const auto PWORKSPACE = header.pWindow->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow) if (PWORKSPACE->m_bHasFullscreenWindow)
return; return;
@@ -1318,7 +1340,7 @@ void CKeybindManager::swapSplit(std::string args) {
if (!header.pWindow) if (!header.pWindow)
return; return;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID); const auto PWORKSPACE = header.pWindow->m_pWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow) if (PWORKSPACE->m_bHasFullscreenWindow)
return; return;
@@ -1426,7 +1448,7 @@ void CKeybindManager::moveCursor(std::string args) {
void CKeybindManager::workspaceOpt(std::string args) { void CKeybindManager::workspaceOpt(std::string args) {
// current workspace // current workspace
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
if (!PWORKSPACE) if (!PWORKSPACE)
return; // ???? return; // ????
@@ -1436,7 +1458,7 @@ void CKeybindManager::workspaceOpt(std::string args) {
// apply // apply
for (auto& w : g_pCompositor->m_vWindows) { for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->m_iWorkspaceID != PWORKSPACE->m_iID) if (!w->m_bIsMapped || w->m_pWorkspace != PWORKSPACE)
continue; continue;
w->m_bIsPseudotiled = PWORKSPACE->m_bDefaultPseudo; w->m_bIsPseudotiled = PWORKSPACE->m_bDefaultPseudo;
@@ -1451,7 +1473,7 @@ void CKeybindManager::workspaceOpt(std::string args) {
ptrs.push_back(w.get()); ptrs.push_back(w.get());
for (auto& w : ptrs) { for (auto& w : ptrs) {
if (!w->m_bIsMapped || w->m_iWorkspaceID != PWORKSPACE->m_iID || w->isHidden()) if (!w->m_bIsMapped || w->m_pWorkspace != PWORKSPACE || w->isHidden())
continue; continue;
if (!w->m_bRequestsFloat && w->m_bIsFloating != PWORKSPACE->m_bDefaultFloating) { if (!w->m_bRequestsFloat && w->m_bIsFloating != PWORKSPACE->m_bDefaultFloating) {
@@ -1493,7 +1515,7 @@ void CKeybindManager::renameWorkspace(std::string args) {
} }
void CKeybindManager::exitHyprland(std::string argz) { void CKeybindManager::exitHyprland(std::string argz) {
g_pInputManager->m_bExitTriggered = true; g_pCompositor->m_bExitTriggered = true;
} }
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
@@ -1505,7 +1527,7 @@ void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
} }
// get the current workspace // get the current workspace
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PCURRENTWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
if (!PCURRENTWORKSPACE) { if (!PCURRENTWORKSPACE) {
Debug::log(ERR, "moveCurrentWorkspaceToMonitor invalid workspace!"); Debug::log(ERR, "moveCurrentWorkspaceToMonitor invalid workspace!");
@@ -1574,7 +1596,7 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
static auto PBACKANDFORTH = CConfigValue<Hyprlang::INT>("binds:workspace_back_and_forth"); static auto PBACKANDFORTH = CConfigValue<Hyprlang::INT>("binds:workspace_back_and_forth");
if (*PBACKANDFORTH && PCURRMONITOR->activeWorkspace == workspaceID && pWorkspace->m_sPrevWorkspace.iID != -1) { if (*PBACKANDFORTH && PCURRMONITOR->activeWorkspaceID() == workspaceID && pWorkspace->m_sPrevWorkspace.iID != -1) {
const int PREVWORKSPACEID = pWorkspace->m_sPrevWorkspace.iID; const int PREVWORKSPACEID = pWorkspace->m_sPrevWorkspace.iID;
const auto PREVWORKSPACENAME = pWorkspace->m_sPrevWorkspace.name; const auto PREVWORKSPACENAME = pWorkspace->m_sPrevWorkspace.name;
// Workspace to focus is previous workspace // Workspace to focus is previous workspace
@@ -1591,7 +1613,7 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"); Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!");
return; return;
} }
if (POLDMONITOR->activeWorkspace == workspaceID) { if (POLDMONITOR->activeWorkspaceID() == workspaceID) {
g_pCompositor->swapActiveWorkspaces(POLDMONITOR, PCURRMONITOR); g_pCompositor->swapActiveWorkspaces(POLDMONITOR, PCURRMONITOR);
return; return;
} else { } else {
@@ -1603,9 +1625,6 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
} }
void CKeybindManager::toggleSpecialWorkspace(std::string args) { void CKeybindManager::toggleSpecialWorkspace(std::string args) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
std::string workspaceName = ""; std::string workspaceName = "";
int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName); int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName);
@@ -1615,11 +1634,11 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) {
} }
bool requestedWorkspaceIsAlreadyOpen = false; bool requestedWorkspaceIsAlreadyOpen = false;
const auto PMONITOR = *PFOLLOWMOUSE == 1 ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->m_pLastMonitor; const auto PMONITOR = g_pCompositor->m_pLastMonitor;
int specialOpenOnMonitor = PMONITOR->specialWorkspaceID; int specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID();
for (auto& m : g_pCompositor->m_vMonitors) { for (auto& m : g_pCompositor->m_vMonitors) {
if (m->specialWorkspaceID == workspaceID) { if (m->activeSpecialWorkspaceID() == workspaceID) {
requestedWorkspaceIsAlreadyOpen = true; requestedWorkspaceIsAlreadyOpen = true;
break; break;
} }
@@ -1732,8 +1751,8 @@ void CKeybindManager::circleNext(std::string arg) {
if (!g_pCompositor->m_pLastWindow) { if (!g_pCompositor->m_pLastWindow) {
// if we have a clear focus, find the first window and get the next focusable. // if we have a clear focus, find the first window and get the next focusable.
if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace) > 0) { if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()) > 0) {
const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID());
switchToWindow(PWINDOW); switchToWindow(PWINDOW);
} }
@@ -1763,13 +1782,13 @@ void CKeybindManager::focusWindow(std::string regexp) {
Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle); Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); const auto PWORKSPACE = PWINDOW->m_pWorkspace;
if (!PWORKSPACE) { if (!PWORKSPACE) {
Debug::log(ERR, "BUG THIS: null workspace in focusWindow"); Debug::log(ERR, "BUG THIS: null workspace in focusWindow");
return; return;
} }
if (g_pCompositor->m_pLastMonitor->activeWorkspace != PWINDOW->m_iWorkspaceID) { if (g_pCompositor->m_pLastMonitor->activeWorkspace != PWINDOW->m_pWorkspace) {
Debug::log(LOG, "Fake executing workspace to move focus"); Debug::log(LOG, "Fake executing workspace to move focus");
changeworkspace(PWORKSPACE->getConfigName()); changeworkspace(PWORKSPACE->getConfigName());
} }
@@ -1957,7 +1976,7 @@ void CKeybindManager::swapnext(std::string arg) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
const auto PLASTCYCLED = g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow->m_pLastCycledWindow) && const auto PLASTCYCLED = g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow->m_pLastCycledWindow) &&
g_pCompositor->m_pLastWindow->m_pLastCycledWindow->m_iWorkspaceID == PLASTWINDOW->m_iWorkspaceID ? g_pCompositor->m_pLastWindow->m_pLastCycledWindow->m_pWorkspace == PLASTWINDOW->m_pWorkspace ?
g_pCompositor->m_pLastWindow->m_pLastCycledWindow : g_pCompositor->m_pLastWindow->m_pLastCycledWindow :
nullptr; nullptr;
@@ -2012,14 +2031,17 @@ void CKeybindManager::pinActive(std::string args) {
return; return;
PWINDOW->m_bPinned = !PWINDOW->m_bPinned; PWINDOW->m_bPinned = !PWINDOW->m_bPinned;
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace; PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
PWINDOW->updateDynamicRules(); PWINDOW->updateDynamicRules();
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); const auto PWORKSPACE = PWINDOW->m_pWorkspace;
PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS); PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS);
g_pEventManager->postEvent(SHyprIPCEvent{"pin", std::format("{:x},{}", (uintptr_t)PWINDOW, (int)PWINDOW->m_bPinned)});
EMIT_HOOK_EVENT("pin", PWINDOW);
} }
void CKeybindManager::mouse(std::string args) { void CKeybindManager::mouse(std::string args) {

View File

@@ -120,6 +120,8 @@ class CKeybindManager {
static uint64_t spawnRaw(std::string); static uint64_t spawnRaw(std::string);
static void toggleActiveFloating(std::string); static void toggleActiveFloating(std::string);
static void toggleActivePseudo(std::string); static void toggleActivePseudo(std::string);
static void setActiveFloating(std::string);
static void setActiveTiled(std::string);
static void changeworkspace(std::string); static void changeworkspace(std::string);
static void fullscreenActive(std::string); static void fullscreenActive(std::string);
static void fakeFullscreenActive(std::string); static void fakeFullscreenActive(std::string);
@@ -177,6 +179,7 @@ class CKeybindManager {
friend class CCompositor; friend class CCompositor;
friend class CInputManager; friend class CInputManager;
friend class CConfigManager; friend class CConfigManager;
friend class CWorkspace;
}; };
inline std::unique_ptr<CKeybindManager> g_pKeybindManager; inline std::unique_ptr<CKeybindManager> g_pKeybindManager;

View File

@@ -74,7 +74,7 @@ void CHyprXWaylandManager::activateWindow(CWindow* pWindow, bool activate) {
} }
if (!pWindow->m_bPinned) if (!pWindow->m_bPinned)
g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID)->m_pLastFocusedWindow = pWindow; pWindow->m_pWorkspace->m_pLastFocusedWindow = pWindow;
} }
void CHyprXWaylandManager::getGeometryForWindow(CWindow* pWindow, CBox* pbox) { void CHyprXWaylandManager::getGeometryForWindow(CWindow* pWindow, CBox* pbox) {

View File

@@ -0,0 +1,82 @@
#include "EventLoopManager.hpp"
#include "../../debug/Log.hpp"
#include <algorithm>
#include <limits>
#include <sys/timerfd.h>
#include <time.h>
#define TIMESPEC_NSEC_PER_SEC 1000000000L
CEventLoopManager::CEventLoopManager() {
m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
}
static int timerWrite(int fd, uint32_t mask, void* data) {
g_pEventLoopManager->onTimerFire();
return 1;
}
void CEventLoopManager::enterLoop(wl_display* display, wl_event_loop* wlEventLoop) {
m_sWayland.loop = wlEventLoop;
m_sWayland.display = display;
wl_event_loop_add_fd(wlEventLoop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr);
wl_display_run(display);
Debug::log(LOG, "Kicked off the event loop! :(");
}
void CEventLoopManager::onTimerFire() {
for (auto& t : m_sTimers.timers) {
if (t->passed() && !t->cancelled())
t->call(t);
}
nudgeTimers();
}
void CEventLoopManager::addTimer(std::shared_ptr<CEventLoopTimer> timer) {
m_sTimers.timers.push_back(timer);
nudgeTimers();
}
void CEventLoopManager::removeTimer(std::shared_ptr<CEventLoopTimer> timer) {
std::erase_if(m_sTimers.timers, [timer](const auto& t) { return timer == t; });
nudgeTimers();
}
static void timespecAddNs(timespec* pTimespec, int64_t delta) {
int delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC;
int delta_s_high = delta / TIMESPEC_NSEC_PER_SEC;
pTimespec->tv_sec += delta_s_high;
pTimespec->tv_nsec += (long)delta_ns_low;
if (pTimespec->tv_nsec >= TIMESPEC_NSEC_PER_SEC) {
pTimespec->tv_nsec -= TIMESPEC_NSEC_PER_SEC;
++pTimespec->tv_sec;
}
}
void CEventLoopManager::nudgeTimers() {
long nextTimerUs = 10 * 1000 * 1000; // 10s
for (auto& t : m_sTimers.timers) {
if (const auto µs = t->leftUs(); µs < nextTimerUs)
nextTimerUs = µs;
}
nextTimerUs = std::clamp(nextTimerUs + 1, 1L, std::numeric_limits<long>::max());
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
timespecAddNs(&now, nextTimerUs * 1000L);
itimerspec ts = {.it_value = now};
timerfd_settime(m_sTimers.timerfd, TFD_TIMER_ABSTIME, &ts, nullptr);
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include <condition_variable>
#include <mutex>
#include <memory>
#include <thread>
#include <wayland-server.h>
#include "EventLoopTimer.hpp"
class CEventLoopManager {
public:
CEventLoopManager();
void enterLoop(wl_display* display, wl_event_loop* wlEventLoop);
void addTimer(std::shared_ptr<CEventLoopTimer> timer);
void removeTimer(std::shared_ptr<CEventLoopTimer> timer);
void onTimerFire();
// recalculates timers
void nudgeTimers();
private:
struct {
wl_event_loop* loop = nullptr;
wl_display* display = nullptr;
} m_sWayland;
struct {
std::vector<std::shared_ptr<CEventLoopTimer>> timers;
int timerfd = -1;
} m_sTimers;
};
inline std::unique_ptr<CEventLoopManager> g_pEventLoopManager;

View File

@@ -0,0 +1,53 @@
#include "EventLoopTimer.hpp"
#include <limits>
#include "EventLoopManager.hpp"
CEventLoopTimer::CEventLoopTimer(std::optional<std::chrono::system_clock::duration> timeout, std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb_,
void* data_) :
cb(cb_),
data(data_) {
if (!timeout.has_value())
expires.reset();
else
expires = std::chrono::system_clock::now() + *timeout;
}
void CEventLoopTimer::updateTimeout(std::optional<std::chrono::system_clock::duration> timeout) {
if (!timeout.has_value()) {
expires.reset();
g_pEventLoopManager->nudgeTimers();
return;
}
expires = std::chrono::system_clock::now() + *timeout;
g_pEventLoopManager->nudgeTimers();
}
bool CEventLoopTimer::passed() {
if (!expires.has_value())
return false;
return std::chrono::system_clock::now() > *expires;
}
void CEventLoopTimer::cancel() {
wasCancelled = true;
expires.reset();
}
bool CEventLoopTimer::cancelled() {
return wasCancelled;
}
void CEventLoopTimer::call(std::shared_ptr<CEventLoopTimer> self) {
expires.reset();
cb(self, data);
}
float CEventLoopTimer::leftUs() {
if (!expires.has_value())
return std::numeric_limits<float>::max();
return std::chrono::duration_cast<std::chrono::microseconds>(*expires - std::chrono::system_clock::now()).count();
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <chrono>
#include <functional>
#include <optional>
class CEventLoopTimer {
public:
CEventLoopTimer(std::optional<std::chrono::system_clock::duration> timeout, std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb_, void* data_);
// if not specified, disarms.
// if specified, arms.
void updateTimeout(std::optional<std::chrono::system_clock::duration> timeout);
void cancel();
bool passed();
float leftUs();
bool cancelled();
// resets expires
void call(std::shared_ptr<CEventLoopTimer> self);
private:
std::function<void(std::shared_ptr<CEventLoopTimer> self, void* data)> cb;
void* data = nullptr;
std::optional<std::chrono::system_clock::time_point> expires;
bool wasCancelled = false;
};

View File

@@ -10,6 +10,16 @@ void Events::listener_newIdleInhibitor(wl_listener* listener, void* data) {
g_pInputManager->newIdleInhibitor(WLRIDLEINHIBITOR); g_pInputManager->newIdleInhibitor(WLRIDLEINHIBITOR);
} }
static void destroyInhibitor(SIdleInhibitor* inhibitor) {
g_pHookSystem->unhook(inhibitor->onWindowDestroy);
g_pInputManager->m_lIdleInhibitors.remove(*inhibitor);
Debug::log(LOG, "Destroyed an idleinhibitor");
g_pInputManager->recheckIdleInhibitorStatus();
}
void CInputManager::newIdleInhibitor(wlr_idle_inhibitor_v1* pInhibitor) { void CInputManager::newIdleInhibitor(wlr_idle_inhibitor_v1* pInhibitor) {
const auto PINHIBIT = &m_lIdleInhibitors.emplace_back(); const auto PINHIBIT = &m_lIdleInhibitors.emplace_back();
@@ -17,16 +27,17 @@ void CInputManager::newIdleInhibitor(wlr_idle_inhibitor_v1* pInhibitor) {
PINHIBIT->pWlrInhibitor = pInhibitor; PINHIBIT->pWlrInhibitor = pInhibitor;
PINHIBIT->onWindowDestroy = g_pHookSystem->hookDynamic("closeWindow", [PINHIBIT](void* self, SCallbackInfo& info, std::any data) {
if (PINHIBIT->pWindow == std::any_cast<CWindow*>(data))
destroyInhibitor(PINHIBIT);
});
PINHIBIT->hyprListener_Destroy.initCallback( PINHIBIT->hyprListener_Destroy.initCallback(
&pInhibitor->events.destroy, &pInhibitor->events.destroy,
[](void* owner, void* data) { [](void* owner, void* data) {
const auto PINH = (SIdleInhibitor*)owner; const auto PINH = (SIdleInhibitor*)owner;
g_pInputManager->m_lIdleInhibitors.remove(*PINH); destroyInhibitor(PINH);
Debug::log(LOG, "Destroyed an idleinhibitor");
g_pInputManager->recheckIdleInhibitorStatus();
}, },
PINHIBIT, "IdleInhibitor"); PINHIBIT, "IdleInhibitor");
@@ -65,7 +76,7 @@ void CInputManager::recheckIdleInhibitorStatus() {
return; return;
} }
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->m_bIsFullscreen && g_pCompositor->isWorkspaceVisible(w->m_iWorkspaceID)) { if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->m_bIsFullscreen && g_pCompositor->isWorkspaceVisible(w->m_pWorkspace)) {
g_pCompositor->setIdleActivityInhibit(false); g_pCompositor->setIdleActivityInhibit(false);
return; return;
} }

View File

@@ -3,6 +3,7 @@
#include "wlr/types/wlr_switch.h" #include "wlr/types/wlr_switch.h"
#include <ranges> #include <ranges>
#include "../../config/ConfigValue.hpp" #include "../../config/ConfigValue.hpp"
#include "../../desktop/Window.hpp"
CInputManager::~CInputManager() { CInputManager::~CInputManager() {
m_vConstraints.clear(); m_vConstraints.clear();
@@ -158,6 +159,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, CLOSEST.x, CLOSEST.y); wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, CLOSEST.x, CLOSEST.y);
wlr_seat_pointer_send_motion(g_pCompositor->m_sSeat.seat, time, CLOSESTLOCAL.x, CLOSESTLOCAL.y); wlr_seat_pointer_send_motion(g_pCompositor->m_sSeat.seat, time, CLOSESTLOCAL.x, CLOSESTLOCAL.y);
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)time * 1000, 0, 0, 0, 0);
} }
return; return;
@@ -170,32 +172,32 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
updateDragIcon(); updateDragIcon();
if (!m_sDrag.drag && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && m_pLastMouseSurface) { if (!m_sDrag.drag && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && m_pLastMouseSurface) {
if (m_bLastFocusOnLS) {
foundSurface = m_pLastMouseSurface; foundSurface = m_pLastMouseSurface;
pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface); pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface);
if (pFoundLayerSurface) { if (pFoundLayerSurface) {
surfacePos = g_pCompositor->getLayerSurfaceFromSurface(foundSurface)->position; surfacePos = pFoundLayerSurface->position;
m_bFocusHeldByButtons = true; m_bFocusHeldByButtons = true;
m_bRefocusHeldByButtons = refocus; m_bRefocusHeldByButtons = refocus;
} else { } else {
// ? CInputPopup* foundPopup = m_sIMERelay.popupFromSurface(foundSurface);
foundSurface = nullptr; if (foundPopup) {
pFoundLayerSurface = nullptr; surfacePos = foundPopup->globalBox().pos();
} m_bFocusHeldByButtons = true;
m_bRefocusHeldByButtons = refocus;
} else if (g_pCompositor->m_pLastWindow) { } else if (g_pCompositor->m_pLastWindow) {
foundSurface = m_pLastMouseSurface; foundSurface = m_pLastMouseSurface;
pFoundWindow = g_pCompositor->m_pLastWindow; pFoundWindow = g_pCompositor->m_pLastWindow;
surfaceCoords = g_pCompositor->vectorToSurfaceLocal(mouseCoords, pFoundWindow, foundSurface); surfaceCoords = g_pCompositor->vectorToSurfaceLocal(mouseCoords, pFoundWindow, foundSurface);
m_bFocusHeldByButtons = true; m_bFocusHeldByButtons = true;
m_bRefocusHeldByButtons = refocus; m_bRefocusHeldByButtons = refocus;
} }
} }
}
g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal()); g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal());
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor && (*PMOUSEFOCUSMON || refocus)) if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor && (*PMOUSEFOCUSMON || refocus) && !m_pForcedFocus)
g_pCompositor->setActiveMonitor(PMONITOR); g_pCompositor->setActiveMonitor(PMONITOR);
if (g_pSessionLockManager->isSessionLocked()) { if (g_pSessionLockManager->isSessionLocked()) {
@@ -208,16 +210,19 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
surfacePos = PMONITOR->vecPosition; surfacePos = PMONITOR->vecPosition;
} }
if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerPopupSurface(mouseCoords, PMONITOR, &surfaceCoords, &pFoundLayerSurface);
// overlays are above fullscreen // overlays are above fullscreen
if (!foundSurface) if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface); foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface);
// also IME popups // also IME popups
if (!foundSurface) { if (!foundSurface) {
auto popup = g_pCompositor->vectorToIMEPopup(mouseCoords, m_sIMERelay.m_lIMEPopups); auto popup = g_pInputManager->m_sIMERelay.popupFromCoords(mouseCoords);
if (popup) { if (popup) {
foundSurface = popup->pSurface->surface; foundSurface = popup->getWlrSurface();
surfacePos = Vector2D(popup->realX, popup->realY); surfacePos = popup->globalBox().pos();
} }
} }
@@ -226,7 +231,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface); foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface);
// then, we check if the workspace doesnt have a fullscreen window // then, we check if the workspace doesnt have a fullscreen window
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto PWORKSPACE = PMONITOR->activeWorkspace;
if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
@@ -240,7 +245,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (PWINDOWIDEAL && if (PWINDOWIDEAL &&
((PWINDOWIDEAL->m_bIsFloating && PWINDOWIDEAL->m_bCreatedOverFullscreen) /* floating over fullscreen */ ((PWINDOWIDEAL->m_bIsFloating && PWINDOWIDEAL->m_bCreatedOverFullscreen) /* floating over fullscreen */
|| (PMONITOR->specialWorkspaceID == PWINDOWIDEAL->m_iWorkspaceID) /* on an open special workspace */)) || (PMONITOR->activeSpecialWorkspace == PWINDOWIDEAL->m_pWorkspace) /* on an open special workspace */))
pFoundWindow = PWINDOWIDEAL; pFoundWindow = PWINDOWIDEAL;
if (!pFoundWindow->m_bIsX11) { if (!pFoundWindow->m_bIsX11) {
@@ -255,19 +260,29 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// then windows // then windows
if (!foundSurface) { if (!foundSurface) {
if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
if (!foundSurface) {
if (PMONITOR->specialWorkspaceID) { if (PMONITOR->activeSpecialWorkspace) {
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (pFoundWindow && !g_pCompositor->isWorkspaceSpecial(pFoundWindow->m_iWorkspaceID)) { if (pFoundWindow && !pFoundWindow->onSpecialWorkspace()) {
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
} }
} else { } else {
// if we have a maximized window, allow focusing on a bar or something if in reserved area.
if (g_pCompositor->isPointOnReservedArea(mouseCoords, PMONITOR)) {
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &surfaceCoords,
&pFoundLayerSurface);
}
if (!foundSurface) {
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen)) if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen))
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
} }
}
}
} else { } else {
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
} }
@@ -418,10 +433,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
unsetCursorImage(); unsetCursorImage();
} }
if (pFoundLayerSurface && if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 &&
(pFoundLayerSurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE || allowKeyboardRefocus) {
(pFoundLayerSurface->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP && !g_pCompositor->m_pLastWindow)) &&
FOLLOWMOUSE != 3 && allowKeyboardRefocus) {
g_pCompositor->focusSurface(foundSurface); g_pCompositor->focusSurface(foundSurface);
} }
@@ -612,7 +625,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
} }
switch (e->state) { switch (e->state) {
case WLR_BUTTON_PRESSED: case WL_POINTER_BUTTON_STATE_PRESSED:
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
break; break;
@@ -634,7 +647,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
g_pCompositor->changeWindowZOrder(g_pCompositor->m_pLastWindow, true); g_pCompositor->changeWindowZOrder(g_pCompositor->m_pLastWindow, true);
break; break;
case WLR_BUTTON_RELEASED: break; case WL_POINTER_BUTTON_STATE_RELEASED: break;
} }
// notify app if we didnt handle it // notify app if we didnt handle it
@@ -647,7 +660,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) { void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
switch (e->state) { switch (e->state) {
case WLR_BUTTON_PRESSED: { case WL_POINTER_BUTTON_STATE_PRESSED: {
const auto PWINDOW = g_pCompositor->vectorToWindowUnified(getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); const auto PWINDOW = g_pCompositor->vectorToWindowUnified(getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
if (!PWINDOW) { if (!PWINDOW) {
@@ -659,7 +672,7 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
kill(PWINDOW->getPID(), SIGKILL); kill(PWINDOW->getPID(), SIGKILL);
break; break;
} }
case WLR_BUTTON_RELEASED: break; case WL_POINTER_BUTTON_STATE_RELEASED: break;
default: break; default: break;
} }
@@ -668,6 +681,7 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
} }
void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) { void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
static auto POFFWINDOWAXIS = CConfigValue<Hyprlang::INT>("input:off_window_axis_events");
static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor"); static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor");
static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor"); static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor");
@@ -689,6 +703,24 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
if (PWINDOW && PWINDOW->checkInputOnDecos(INPUT_TYPE_AXIS, MOUSECOORDS, e)) if (PWINDOW && PWINDOW->checkInputOnDecos(INPUT_TYPE_AXIS, MOUSECOORDS, e))
return; return;
if (PWINDOW && *POFFWINDOWAXIS != 1) {
const auto BOX = PWINDOW->getWindowMainSurfaceBox();
if (!BOX.containsPoint(MOUSECOORDS) && !PWINDOW->hasPopupAt(MOUSECOORDS)) {
if (*POFFWINDOWAXIS == 0)
return;
const auto TEMPCURX = std::clamp(MOUSECOORDS.x, BOX.x, BOX.x + BOX.w - 1);
const auto TEMPCURY = std::clamp(MOUSECOORDS.y, BOX.y, BOX.y + BOX.h - 1);
if (*POFFWINDOWAXIS == 3)
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, TEMPCURX, TEMPCURY);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, TEMPCURX - BOX.x, TEMPCURY - BOX.y);
wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat);
}
}
} }
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source, wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source,
@@ -1188,9 +1220,6 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
updateKeyboardsLeds(pKeyboard->keyboard); updateKeyboardsLeds(pKeyboard->keyboard);
} }
if (m_bExitTriggered)
g_pCompositor->cleanup();
} }
void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) { void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
@@ -1417,6 +1446,11 @@ void CInputManager::setTabletConfigs() {
Debug::log(LOG, "Setting calibration matrix for device {}", t.name); Debug::log(LOG, "Setting calibration matrix for device {}", t.name);
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]); libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
if (g_pConfigManager->getDeviceInt(t.name, "left_handed", "input:tablet:left_handed") == 0)
libinput_device_config_left_handed_set(LIBINPUTDEV, 0);
else
libinput_device_config_left_handed_set(LIBINPUTDEV, 1);
const auto OUTPUT = g_pConfigManager->getDeviceString(t.name, "output", "input:tablet:output"); const auto OUTPUT = g_pConfigManager->getDeviceString(t.name, "output", "input:tablet:output");
const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT); const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT);
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) { if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) {
@@ -1432,6 +1466,13 @@ void CInputManager::setTabletConfigs() {
auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y}; auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y};
if (!regionBox.empty()) if (!regionBox.empty())
wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr()); wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr());
const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(t.name, "active_area_size", "input:tablet:active_area_size");
const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(t.name, "active_area_position", "input:tablet:active_area_position");
if (ACTIVE_AREA_SIZE.x != 0 || ACTIVE_AREA_SIZE.y != 0) {
t.activeArea = CBox{ACTIVE_AREA_POS.x / t.wlrTablet->width_mm, ACTIVE_AREA_POS.y / t.wlrTablet->height_mm,
(ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t.wlrTablet->width_mm, (ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t.wlrTablet->height_mm};
}
} }
} }
} }

View File

@@ -3,11 +3,11 @@
#include "../../defines.hpp" #include "../../defines.hpp"
#include <list> #include <list>
#include "../../helpers/WLClasses.hpp" #include "../../helpers/WLClasses.hpp"
#include "../../Window.hpp"
#include "../../helpers/Timer.hpp" #include "../../helpers/Timer.hpp"
#include "InputMethodRelay.hpp" #include "InputMethodRelay.hpp"
class CConstraint; class CConstraint;
class CWindow;
enum eClickBehaviorMode { enum eClickBehaviorMode {
CLICKMODE_DEFAULT = 0, CLICKMODE_DEFAULT = 0,
@@ -184,6 +184,8 @@ class CInputManager {
// for some bugs in follow mouse 0 // for some bugs in follow mouse 0
bool m_bLastFocusOnLS = false; bool m_bLastFocusOnLS = false;
bool m_bLastFocusOnIMEPopup = false;
// for hiding cursor on touch // for hiding cursor on touch
bool m_bLastInputTouch = false; bool m_bLastInputTouch = false;
@@ -231,6 +233,8 @@ class CInputManager {
// swipe // swipe
void beginWorkspaceSwipe(); void beginWorkspaceSwipe();
void updateWorkspaceSwipe(double);
void endWorkspaceSwipe();
void setBorderCursorIcon(eBorderIconDirection); void setBorderCursorIcon(eBorderIconDirection);
void setCursorIconOnBorder(CWindow* w); void setCursorIconOnBorder(CWindow* w);
@@ -249,8 +253,6 @@ class CInputManager {
void restoreCursorIconToApp(); // no-op if restored void restoreCursorIconToApp(); // no-op if restored
bool m_bExitTriggered = false; // for exit dispatcher
friend class CKeybindManager; friend class CKeybindManager;
friend class CWLSurface; friend class CWLSurface;
}; };

View File

@@ -0,0 +1,183 @@
#include "InputMethodPopup.hpp"
#include "InputManager.hpp"
#include "../../Compositor.hpp"
CInputPopup::CInputPopup(wlr_input_popup_surface_v2* surf) : pWlr(surf) {
surface.assign(surf->surface);
initCallbacks();
}
static void onCommit(void* owner, void* data) {
const auto PPOPUP = (CInputPopup*)owner;
PPOPUP->onCommit();
}
static void onMap(void* owner, void* data) {
const auto PPOPUP = (CInputPopup*)owner;
PPOPUP->onMap();
}
static void onUnmap(void* owner, void* data) {
const auto PPOPUP = (CInputPopup*)owner;
PPOPUP->onUnmap();
}
static void onDestroy(void* owner, void* data) {
const auto PPOPUP = (CInputPopup*)owner;
PPOPUP->onDestroy();
}
void CInputPopup::initCallbacks() {
hyprListener_commitPopup.initCallback(&pWlr->surface->events.commit, &::onCommit, this, "IME Popup");
hyprListener_mapPopup.initCallback(&pWlr->surface->events.map, &::onMap, this, "IME Popup");
hyprListener_unmapPopup.initCallback(&pWlr->surface->events.unmap, &::onUnmap, this, "IME Popup");
hyprListener_destroyPopup.initCallback(&pWlr->events.destroy, &::onDestroy, this, "IME Popup");
}
CWLSurface* CInputPopup::queryOwner() {
const auto FOCUSED = g_pInputManager->m_sIMERelay.getFocusedTextInput();
if (!FOCUSED)
return nullptr;
return CWLSurface::surfaceFromWlr(FOCUSED->focusedSurface());
}
void CInputPopup::onDestroy() {
hyprListener_commitPopup.removeCallback();
hyprListener_destroyPopup.removeCallback();
hyprListener_mapPopup.removeCallback();
hyprListener_unmapPopup.removeCallback();
g_pInputManager->m_sIMERelay.removePopup(this);
}
void CInputPopup::onMap() {
Debug::log(LOG, "Mapped an IME Popup");
updateBox();
damageEntire();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(globalBox().middle());
if (!PMONITOR)
return;
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(surface.wlr(), PMONITOR->scale);
}
void CInputPopup::onUnmap() {
Debug::log(LOG, "Unmapped an IME Popup");
damageEntire();
}
void CInputPopup::onCommit() {
updateBox();
}
void CInputPopup::damageEntire() {
const auto OWNER = queryOwner();
if (!OWNER) {
Debug::log(ERR, "BUG THIS: No owner in imepopup::damageentire");
return;
}
CBox box = globalBox();
g_pHyprRenderer->damageBox(&box);
}
void CInputPopup::damageSurface() {
const auto OWNER = queryOwner();
if (!OWNER) {
Debug::log(ERR, "BUG THIS: No owner in imepopup::damagesurface");
return;
}
Vector2D pos = globalBox().pos();
g_pHyprRenderer->damageSurface(surface.wlr(), pos.x, pos.y);
}
void CInputPopup::updateBox() {
if (!surface.wlr()->mapped)
return;
const auto OWNER = queryOwner();
const auto PFOCUSEDTI = g_pInputManager->m_sIMERelay.getFocusedTextInput();
if (!PFOCUSEDTI)
return;
bool cursorRect = PFOCUSEDTI->hasCursorRectangle();
CBox cursorBoxParent = PFOCUSEDTI->cursorBox();
CBox parentBox;
if (!OWNER)
parentBox = {0, 0, 500, 500};
else
parentBox = OWNER->getSurfaceBoxGlobal().value_or(CBox{0, 0, 500, 500});
if (!cursorRect) {
Vector2D coords = OWNER ? OWNER->getSurfaceBoxGlobal().value_or(CBox{0, 0, 500, 500}).pos() : Vector2D{0, 0};
parentBox = {coords, {500, 500}};
cursorBoxParent = {0, 0, (int)parentBox.w, (int)parentBox.h};
}
Vector2D currentPopupSize = surface.getViewporterCorrectedSize();
CMonitor* pMonitor = g_pCompositor->getMonitorFromVector(parentBox.middle());
Vector2D popupOffset(0, 0);
if (parentBox.y + cursorBoxParent.y + cursorBoxParent.height + currentPopupSize.y > pMonitor->vecPosition.y + pMonitor->vecSize.y)
popupOffset.y = -currentPopupSize.y;
else
popupOffset.y = cursorBoxParent.height;
double popupOverflow = parentBox.x + cursorBoxParent.x + currentPopupSize.x - (pMonitor->vecPosition.x + pMonitor->vecSize.x);
if (popupOverflow > 0)
popupOffset.x -= popupOverflow;
CBox cursorBoxLocal({-popupOffset.x, -popupOffset.y}, cursorBoxParent.size());
wlr_input_popup_surface_v2_send_text_input_rectangle(pWlr, cursorBoxLocal.pWlr());
CBox popupBoxParent(cursorBoxParent.pos() + popupOffset, currentPopupSize);
if (popupBoxParent != lastBoxLocal) {
damageEntire();
lastBoxLocal = popupBoxParent;
}
damageSurface();
if (const auto PM = g_pCompositor->getMonitorFromCursor(); PM && PM->ID != lastMonitor) {
const auto PML = g_pCompositor->getMonitorFromID(lastMonitor);
if (PML)
wlr_surface_send_leave(surface.wlr(), PML->output);
wlr_surface_send_enter(surface.wlr(), PM->output);
lastMonitor = PM->ID;
}
}
CBox CInputPopup::globalBox() {
const auto OWNER = queryOwner();
if (!OWNER) {
Debug::log(ERR, "BUG THIS: No owner in imepopup::globalbox");
return {};
}
CBox parentBox = OWNER->getSurfaceBoxGlobal().value_or(CBox{0, 0, 500, 500});
return lastBoxLocal.copy().translate(parentBox.pos());
}
bool CInputPopup::isVecInPopup(const Vector2D& point) {
return globalBox().containsPoint(point);
}
wlr_surface* CInputPopup::getWlrSurface() {
return surface.wlr();
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include "../../helpers/WLListener.hpp"
#include "../../desktop/WLSurface.hpp"
#include "../../macros.hpp"
#include "../../helpers/Box.hpp"
struct wlr_input_popup_surface_v2;
class CInputPopup {
public:
CInputPopup(wlr_input_popup_surface_v2* surf);
void onDestroy();
void onMap();
void onUnmap();
void onCommit();
void damageEntire();
void damageSurface();
bool isVecInPopup(const Vector2D& point);
CBox globalBox();
wlr_surface* getWlrSurface();
private:
void initCallbacks();
CWLSurface* queryOwner();
void updateBox();
wlr_input_popup_surface_v2* pWlr = nullptr;
CWLSurface surface;
CBox lastBoxLocal;
uint64_t lastMonitor = -1;
DYNLISTENER(mapPopup);
DYNLISTENER(unmapPopup);
DYNLISTENER(destroyPopup);
DYNLISTENER(commitPopup);
};

View File

@@ -28,46 +28,7 @@ void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) {
return; return;
} }
if (PTI->pWlrInput) { PTI->updateIMEState(PIMR->m_pWLRIME);
if (PIMR->m_pWLRIME->current.preedit.text) {
wlr_text_input_v3_send_preedit_string(PTI->pWlrInput, PIMR->m_pWLRIME->current.preedit.text, PIMR->m_pWLRIME->current.preedit.cursor_begin,
PIMR->m_pWLRIME->current.preedit.cursor_end);
}
if (PIMR->m_pWLRIME->current.commit_text) {
wlr_text_input_v3_send_commit_string(PTI->pWlrInput, PIMR->m_pWLRIME->current.commit_text);
}
if (PIMR->m_pWLRIME->current.delete_.before_length || PIMR->m_pWLRIME->current.delete_.after_length) {
wlr_text_input_v3_send_delete_surrounding_text(PTI->pWlrInput, PIMR->m_pWLRIME->current.delete_.before_length, PIMR->m_pWLRIME->current.delete_.after_length);
}
wlr_text_input_v3_send_done(PTI->pWlrInput);
} else {
if (PIMR->m_pWLRIME->current.preedit.text) {
zwp_text_input_v1_send_preedit_cursor(PTI->pV1Input->resourceImpl, PIMR->m_pWLRIME->current.preedit.cursor_begin);
zwp_text_input_v1_send_preedit_styling(PTI->pV1Input->resourceImpl, 0, std::string(PIMR->m_pWLRIME->current.preedit.text).length(),
ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT);
zwp_text_input_v1_send_preedit_string(PTI->pV1Input->resourceImpl, PTI->pV1Input->serial, PIMR->m_pWLRIME->current.preedit.text, "");
} else {
zwp_text_input_v1_send_preedit_cursor(PTI->pV1Input->resourceImpl, PIMR->m_pWLRIME->current.preedit.cursor_begin);
zwp_text_input_v1_send_preedit_styling(PTI->pV1Input->resourceImpl, 0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT);
zwp_text_input_v1_send_preedit_string(PTI->pV1Input->resourceImpl, PTI->pV1Input->serial, "", "");
}
if (PIMR->m_pWLRIME->current.commit_text) {
zwp_text_input_v1_send_commit_string(PTI->pV1Input->resourceImpl, PTI->pV1Input->serial, PIMR->m_pWLRIME->current.commit_text);
}
if (PIMR->m_pWLRIME->current.delete_.before_length || PIMR->m_pWLRIME->current.delete_.after_length) {
zwp_text_input_v1_send_delete_surrounding_text(PTI->pV1Input->resourceImpl,
std::string(PIMR->m_pWLRIME->current.preedit.text).length() - PIMR->m_pWLRIME->current.delete_.before_length,
PIMR->m_pWLRIME->current.delete_.after_length + PIMR->m_pWLRIME->current.delete_.before_length);
if (PIMR->m_pWLRIME->current.preedit.text)
zwp_text_input_v1_send_commit_string(PTI->pV1Input->resourceImpl, PTI->pV1Input->serial, PIMR->m_pWLRIME->current.preedit.text);
}
}
}, },
this, "IMERelay"); this, "IMERelay");
@@ -87,14 +48,8 @@ void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) {
Debug::log(LOG, "IME Destroy"); Debug::log(LOG, "IME Destroy");
if (PTI) { if (PTI)
setPendingSurface(PTI, focusedSurface(PTI)); PTI->leave();
if (PTI->pWlrInput)
wlr_text_input_v3_send_leave(PTI->pWlrInput);
else
zwp_text_input_v1_send_leave(PTI->pV1Input->resourceImpl);
}
}, },
this, "IMERelay"); this, "IMERelay");
@@ -131,178 +86,32 @@ void CInputMethodRelay::onNewIME(wlr_input_method_v2* pIME) {
hyprListener_IMENewPopup.initCallback( hyprListener_IMENewPopup.initCallback(
&m_pWLRIME->events.new_popup_surface, &m_pWLRIME->events.new_popup_surface,
[&](void* owner, void* data) { [&](void* owner, void* data) {
const auto PNEWPOPUP = &m_lIMEPopups.emplace_back(); m_vIMEPopups.emplace_back(std::make_unique<CInputPopup>((wlr_input_popup_surface_v2*)data));
PNEWPOPUP->pSurface = (wlr_input_popup_surface_v2*)data;
PNEWPOPUP->hyprListener_commitPopup.initCallback(&PNEWPOPUP->pSurface->surface->events.commit, &Events::listener_commitInputPopup, PNEWPOPUP, "IME Popup");
PNEWPOPUP->hyprListener_mapPopup.initCallback(&PNEWPOPUP->pSurface->surface->events.map, &Events::listener_mapInputPopup, PNEWPOPUP, "IME Popup");
PNEWPOPUP->hyprListener_unmapPopup.initCallback(&PNEWPOPUP->pSurface->surface->events.unmap, &Events::listener_unmapInputPopup, PNEWPOPUP, "IME Popup");
PNEWPOPUP->hyprListener_destroyPopup.initCallback(&PNEWPOPUP->pSurface->events.destroy, &Events::listener_destroyInputPopup, PNEWPOPUP, "IME Popup");
Debug::log(LOG, "New input popup"); Debug::log(LOG, "New input popup");
}, },
this, "IMERelay"); this, "IMERelay");
const auto PTI = getFocusableTextInput(); if (!g_pCompositor->m_pLastFocus)
return;
if (PTI) { for (auto& ti : m_vTextInputs) {
if (PTI->pWlrInput) if (ti->client() != wl_resource_get_client(g_pCompositor->m_pLastFocus->resource))
wlr_text_input_v3_send_enter(PTI->pWlrInput, PTI->pPendingSurface); continue;
if (ti->isV3())
ti->enter(g_pCompositor->m_pLastFocus);
else else
zwp_text_input_v1_send_enter(PTI->pV1Input->resourceImpl, PTI->pPendingSurface->resource); ti->onEnabled(g_pCompositor->m_pLastFocus);
setPendingSurface(PTI, nullptr);
} }
} }
wlr_surface* CInputMethodRelay::focusedSurface(STextInput* pTI) { void CInputMethodRelay::setIMEPopupFocus(CInputPopup* pPopup, wlr_surface* pSurface) {
return pTI->pWlrInput ? pTI->pWlrInput->focused_surface : pTI->pV1Input->focusedSurface; pPopup->onCommit();
} }
void CInputMethodRelay::updateInputPopup(SIMEPopup* pPopup) { void CInputMethodRelay::removePopup(CInputPopup* pPopup) {
if (!pPopup->pSurface->surface->mapped) std::erase_if(m_vIMEPopups, [pPopup](const auto& other) { return other.get() == pPopup; });
return;
// damage last known pos & size
g_pHyprRenderer->damageBox(pPopup->realX, pPopup->realY, pPopup->lastSize.x, pPopup->lastSize.y);
const auto PFOCUSEDTI = getFocusedTextInput();
if (!PFOCUSEDTI || !focusedSurface(PFOCUSEDTI))
return;
bool cursorRect = PFOCUSEDTI->pWlrInput ? PFOCUSEDTI->pWlrInput->current.features & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE : true;
const auto PFOCUSEDSURFACE = focusedSurface(PFOCUSEDTI);
CBox cursorBox = PFOCUSEDTI->pWlrInput ? PFOCUSEDTI->pWlrInput->current.cursor_rectangle : PFOCUSEDTI->pV1Input->cursorRectangle;
CMonitor* pMonitor = nullptr;
Vector2D parentPos;
Vector2D parentSize;
if (wlr_layer_surface_v1_try_from_wlr_surface(PFOCUSEDSURFACE)) {
const auto PLS = g_pCompositor->getLayerSurfaceFromWlr(wlr_layer_surface_v1_try_from_wlr_surface(PFOCUSEDSURFACE));
if (PLS) {
parentPos = Vector2D(PLS->geometry.x, PLS->geometry.y) + g_pCompositor->getMonitorFromID(PLS->monitorID)->vecPosition;
parentSize = Vector2D(PLS->geometry.width, PLS->geometry.height);
pMonitor = g_pCompositor->getMonitorFromID(PLS->monitorID);
}
} else {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(PFOCUSEDSURFACE);
if (PWINDOW) {
parentPos = PWINDOW->m_vRealPosition.goal();
parentSize = PWINDOW->m_vRealSize.goal();
pMonitor = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
}
}
if (!cursorRect) {
cursorBox = {0, 0, (int)parentSize.x, (int)parentSize.y};
}
if (!pMonitor)
return;
CBox finalBox = cursorBox;
if (cursorBox.y + parentPos.y + pPopup->pSurface->surface->current.height + finalBox.height > pMonitor->vecPosition.y + pMonitor->vecSize.y)
finalBox.y -= pPopup->pSurface->surface->current.height + finalBox.height;
if (cursorBox.x + parentPos.x + pPopup->pSurface->surface->current.width > pMonitor->vecPosition.x + pMonitor->vecSize.x)
finalBox.x -= (cursorBox.x + parentPos.x + pPopup->pSurface->surface->current.width) - (pMonitor->vecPosition.x + pMonitor->vecSize.x);
pPopup->x = finalBox.x;
pPopup->y = finalBox.y + finalBox.height;
pPopup->realX = finalBox.x + parentPos.x;
pPopup->realY = finalBox.y + parentPos.y + finalBox.height;
pPopup->lastSize = Vector2D(pPopup->pSurface->surface->current.width, pPopup->pSurface->surface->current.height);
wlr_input_popup_surface_v2_send_text_input_rectangle(pPopup->pSurface, finalBox.pWlr());
damagePopup(pPopup);
}
void CInputMethodRelay::setIMEPopupFocus(SIMEPopup* pPopup, wlr_surface* pSurface) {
updateInputPopup(pPopup);
}
void Events::listener_mapInputPopup(void* owner, void* data) {
const auto PPOPUP = (SIMEPopup*)owner;
Debug::log(LOG, "Mapped an IME Popup");
g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP);
if (const auto PMONITOR = g_pCompositor->getMonitorFromVector(Vector2D(PPOPUP->realX, PPOPUP->realY) + PPOPUP->lastSize / 2.f); PMONITOR)
wlr_surface_send_enter(PPOPUP->pSurface->surface, PMONITOR->output);
}
void Events::listener_unmapInputPopup(void* owner, void* data) {
const auto PPOPUP = (SIMEPopup*)owner;
Debug::log(LOG, "Unmapped an IME Popup");
g_pHyprRenderer->damageBox(PPOPUP->realX, PPOPUP->realY, PPOPUP->lastSize.x, PPOPUP->lastSize.y);
g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP);
}
void Events::listener_destroyInputPopup(void* owner, void* data) {
const auto PPOPUP = (SIMEPopup*)owner;
Debug::log(LOG, "Removed an IME Popup");
PPOPUP->hyprListener_commitPopup.removeCallback();
PPOPUP->hyprListener_destroyPopup.removeCallback();
PPOPUP->hyprListener_focusedSurfaceUnmap.removeCallback();
PPOPUP->hyprListener_mapPopup.removeCallback();
PPOPUP->hyprListener_unmapPopup.removeCallback();
g_pInputManager->m_sIMERelay.removePopup(PPOPUP);
}
void Events::listener_commitInputPopup(void* owner, void* data) {
const auto PPOPUP = (SIMEPopup*)owner;
g_pInputManager->m_sIMERelay.updateInputPopup(PPOPUP);
}
void CInputMethodRelay::removePopup(SIMEPopup* pPopup) {
m_lIMEPopups.remove(*pPopup);
}
void CInputMethodRelay::damagePopup(SIMEPopup* pPopup) {
if (!pPopup->pSurface->surface->mapped)
return;
const auto PFOCUSEDTI = getFocusedTextInput();
if (!PFOCUSEDTI || !focusedSurface(PFOCUSEDTI))
return;
Vector2D parentPos;
const auto PFOCUSEDSURFACE = focusedSurface(PFOCUSEDTI);
if (wlr_layer_surface_v1_try_from_wlr_surface(PFOCUSEDSURFACE)) {
const auto PLS = g_pCompositor->getLayerSurfaceFromWlr(wlr_layer_surface_v1_try_from_wlr_surface(PFOCUSEDSURFACE));
if (PLS) {
parentPos = Vector2D(PLS->geometry.x, PLS->geometry.y) + g_pCompositor->getMonitorFromID(PLS->monitorID)->vecPosition;
}
} else {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(PFOCUSEDSURFACE);
if (PWINDOW) {
parentPos = PWINDOW->m_vRealPosition.goal();
}
}
g_pHyprRenderer->damageSurface(pPopup->pSurface->surface, parentPos.x + pPopup->x, parentPos.y + pPopup->y);
} }
SIMEKbGrab* CInputMethodRelay::getIMEKeyboardGrab(SKeyboard* pKeyboard) { SIMEKbGrab* CInputMethodRelay::getIMEKeyboardGrab(SKeyboard* pKeyboard) {
@@ -321,221 +130,103 @@ SIMEKbGrab* CInputMethodRelay::getIMEKeyboardGrab(SKeyboard* pKeyboard) {
return m_pKeyboardGrab.get(); return m_pKeyboardGrab.get();
} }
STextInput* CInputMethodRelay::getFocusedTextInput() { CTextInput* CInputMethodRelay::getFocusedTextInput() {
if (!g_pCompositor->m_pLastFocus)
for (auto& ti : m_lTextInputs) {
if (focusedSurface(&ti)) {
return &ti;
}
}
return nullptr; return nullptr;
}
STextInput* CInputMethodRelay::getFocusableTextInput() { for (auto& ti : m_vTextInputs) {
for (auto& ti : m_lTextInputs) { if (ti->focusedSurface() == g_pCompositor->m_pLastFocus)
if (ti.pPendingSurface) { return ti.get();
return &ti;
}
} }
return nullptr; return nullptr;
} }
void CInputMethodRelay::onNewTextInput(wlr_text_input_v3* pInput) { void CInputMethodRelay::onNewTextInput(wlr_text_input_v3* pInput) {
createNewTextInput(pInput); m_vTextInputs.emplace_back(std::make_unique<CTextInput>(pInput));
} }
void CInputMethodRelay::createNewTextInput(wlr_text_input_v3* pInput, STextInputV1* pTIV1) { void CInputMethodRelay::onNewTextInput(STextInputV1* pTIV1) {
const auto PTEXTINPUT = &m_lTextInputs.emplace_back(); m_vTextInputs.emplace_back(std::make_unique<CTextInput>(pTIV1));
PTEXTINPUT->pWlrInput = pInput;
PTEXTINPUT->pV1Input = pTIV1;
if (pTIV1)
pTIV1->pTextInput = PTEXTINPUT;
PTEXTINPUT->hyprListener_textInputEnable.initCallback(
pInput ? &pInput->events.enable : &pTIV1->sEnable,
[](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
// Debug::log(WARN, "Enabling TextInput on no IME!");
return;
} }
Debug::log(LOG, "Enable TextInput"); void CInputMethodRelay::removeTextInput(CTextInput* pInput) {
std::erase_if(m_vTextInputs, [pInput](const auto& other) { return other.get() == pInput; });
wlr_input_method_v2_send_activate(g_pInputManager->m_sIMERelay.m_pWLRIME);
g_pInputManager->m_sIMERelay.commitIMEState(PINPUT);
},
PTEXTINPUT, "textInput");
PTEXTINPUT->hyprListener_textInputCommit.initCallback(
pInput ? &pInput->events.commit : &pTIV1->sCommit,
[](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
// Debug::log(WARN, "Committing TextInput on no IME!");
return;
} }
if (!(PINPUT->pWlrInput ? PINPUT->pWlrInput->current_enabled : PINPUT->pV1Input->active)) { void CInputMethodRelay::updateAllPopups() {
Debug::log(WARN, "Disabled TextInput commit?"); for (auto& p : m_vIMEPopups) {
return; p->onCommit();
}
} }
g_pInputManager->m_sIMERelay.commitIMEState(PINPUT); void CInputMethodRelay::activateIME(CTextInput* pInput) {
},
PTEXTINPUT, "textInput");
PTEXTINPUT->hyprListener_textInputDisable.initCallback(
pInput ? &pInput->events.disable : &pTIV1->sDisable,
[](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
// Debug::log(WARN, "Disabling TextInput on no IME!");
return;
}
Debug::log(LOG, "Disable TextInput");
wlr_input_method_v2_send_deactivate(g_pInputManager->m_sIMERelay.m_pWLRIME);
g_pInputManager->m_sIMERelay.commitIMEState(PINPUT);
},
PTEXTINPUT, "textInput");
PTEXTINPUT->hyprListener_textInputDestroy.initCallback(
pInput ? &pInput->events.destroy : &pTIV1->sDestroy,
[](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
// Debug::log(WARN, "Disabling TextInput on no IME!");
return;
}
if (PINPUT->pWlrInput && PINPUT->pWlrInput->current_enabled) {
wlr_input_method_v2_send_deactivate(g_pInputManager->m_sIMERelay.m_pWLRIME);
g_pInputManager->m_sIMERelay.commitIMEState(PINPUT);
}
g_pInputManager->m_sIMERelay.setPendingSurface(PINPUT, nullptr);
PINPUT->hyprListener_textInputCommit.removeCallback();
PINPUT->hyprListener_textInputDestroy.removeCallback();
PINPUT->hyprListener_textInputDisable.removeCallback();
PINPUT->hyprListener_textInputEnable.removeCallback();
g_pInputManager->m_sIMERelay.removeTextInput(PINPUT);
},
PTEXTINPUT, "textInput");
}
void CInputMethodRelay::removeTextInput(STextInput* pInput) {
m_lTextInputs.remove_if([&](const auto& other) { return other.pWlrInput == pInput->pWlrInput && other.pV1Input == pInput->pV1Input; });
}
void CInputMethodRelay::commitIMEState(STextInput* pInput) {
if (!m_pWLRIME) if (!m_pWLRIME)
return; return;
if (pInput->pWlrInput) { wlr_input_method_v2_send_activate(g_pInputManager->m_sIMERelay.m_pWLRIME);
// V3 commitIMEState(pInput);
if (pInput->pWlrInput->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT)
wlr_input_method_v2_send_surrounding_text(m_pWLRIME, pInput->pWlrInput->current.surrounding.text, pInput->pWlrInput->current.surrounding.cursor,
pInput->pWlrInput->current.surrounding.anchor);
wlr_input_method_v2_send_text_change_cause(m_pWLRIME, pInput->pWlrInput->current.text_change_cause);
if (pInput->pWlrInput->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE)
wlr_input_method_v2_send_content_type(m_pWLRIME, pInput->pWlrInput->current.content_type.hint, pInput->pWlrInput->current.content_type.purpose);
} else {
// V1
if (pInput->pV1Input->pendingSurrounding.isPending)
wlr_input_method_v2_send_surrounding_text(m_pWLRIME, pInput->pV1Input->pendingSurrounding.text.c_str(), pInput->pV1Input->pendingSurrounding.cursor,
pInput->pV1Input->pendingSurrounding.anchor);
wlr_input_method_v2_send_text_change_cause(m_pWLRIME, 0);
if (pInput->pV1Input->pendingContentType.isPending)
wlr_input_method_v2_send_content_type(m_pWLRIME, pInput->pV1Input->pendingContentType.hint, pInput->pV1Input->pendingContentType.purpose);
} }
for (auto& p : m_lIMEPopups) { void CInputMethodRelay::deactivateIME(CTextInput* pInput) {
updateInputPopup(&p); if (!m_pWLRIME)
return;
if (!m_pWLRIME->active)
return;
wlr_input_method_v2_send_deactivate(g_pInputManager->m_sIMERelay.m_pWLRIME);
commitIMEState(pInput);
} }
wlr_input_method_v2_send_done(m_pWLRIME); void CInputMethodRelay::commitIMEState(CTextInput* pInput) {
if (!m_pWLRIME)
return;
pInput->commitStateToIME(m_pWLRIME);
} }
void CInputMethodRelay::onKeyboardFocus(wlr_surface* pSurface) { void CInputMethodRelay::onKeyboardFocus(wlr_surface* pSurface) {
if (!m_pWLRIME) if (!m_pWLRIME)
return; return;
auto client = [](STextInput* pTI) -> wl_client* { return pTI->pWlrInput ? wl_resource_get_client(pTI->pWlrInput->resource) : pTI->pV1Input->client; }; if (pSurface == m_pLastKbFocus)
return;
for (auto& ti : m_lTextInputs) { m_pLastKbFocus = pSurface;
if (ti.pPendingSurface) {
if (pSurface != ti.pPendingSurface) for (auto& ti : m_vTextInputs) {
setPendingSurface(&ti, nullptr); if (!ti->focusedSurface())
} else if (focusedSurface(&ti)) {
if (pSurface != focusedSurface(&ti)) {
wlr_input_method_v2_send_deactivate(m_pWLRIME);
commitIMEState(&ti);
if (ti.pWlrInput)
wlr_text_input_v3_send_leave(ti.pWlrInput);
else {
zwp_text_input_v1_send_leave(ti.pV1Input->resourceImpl);
ti.pV1Input->focusedSurface = nullptr;
ti.pV1Input->active = false;
}
} else {
continue; continue;
ti->leave();
}
for (auto& ti : m_vTextInputs) {
if (!ti->isV3())
continue;
if (ti->client() != wl_resource_get_client(pSurface->resource))
continue;
ti->enter(pSurface);
} }
} }
if (pSurface && client(&ti) == wl_resource_get_client(pSurface->resource)) { CInputPopup* CInputMethodRelay::popupFromCoords(const Vector2D& point) {
for (auto& p : m_vIMEPopups) {
if (m_pWLRIME) { if (p->isVecInPopup(point))
if (ti.pWlrInput) return p.get();
wlr_text_input_v3_send_enter(ti.pWlrInput, pSurface);
else {
zwp_text_input_v1_send_enter(ti.pV1Input->resourceImpl, pSurface->resource);
ti.pV1Input->focusedSurface = pSurface;
ti.pV1Input->active = true;
}
} else {
setPendingSurface(&ti, pSurface);
}
}
}
} }
void CInputMethodRelay::setPendingSurface(STextInput* pInput, wlr_surface* pSurface) { return nullptr;
pInput->pPendingSurface = pSurface;
if (pSurface) {
pInput->hyprListener_pendingSurfaceDestroy.initCallback(
&pSurface->events.destroy,
[](void* owner, void* data) {
const auto PINPUT = (STextInput*)owner;
PINPUT->pPendingSurface = nullptr;
PINPUT->hyprListener_pendingSurfaceDestroy.removeCallback();
},
pInput, "TextInput");
} else {
pInput->hyprListener_pendingSurfaceDestroy.removeCallback();
} }
CInputPopup* CInputMethodRelay::popupFromSurface(const wlr_surface* surface) {
for (auto& p : m_vIMEPopups) {
if (p->getWlrSurface() == surface)
return p.get();
}
return nullptr;
} }

View File

@@ -3,8 +3,11 @@
#include <list> #include <list>
#include "../../defines.hpp" #include "../../defines.hpp"
#include "../../helpers/WLClasses.hpp" #include "../../helpers/WLClasses.hpp"
#include "TextInput.hpp"
#include "InputMethodPopup.hpp"
class CInputManager; class CInputManager;
class CHyprRenderer;
struct STextInputV1; struct STextInputV1;
class CInputMethodRelay { class CInputMethodRelay {
@@ -13,31 +16,36 @@ class CInputMethodRelay {
void onNewIME(wlr_input_method_v2*); void onNewIME(wlr_input_method_v2*);
void onNewTextInput(wlr_text_input_v3*); void onNewTextInput(wlr_text_input_v3*);
void onNewTextInput(STextInputV1* pTIV1);
wlr_input_method_v2* m_pWLRIME = nullptr; wlr_input_method_v2* m_pWLRIME = nullptr;
void commitIMEState(STextInput* pInput); void activateIME(CTextInput* pInput);
void removeTextInput(STextInput* pInput); void deactivateIME(CTextInput* pInput);
void commitIMEState(CTextInput* pInput);
void removeTextInput(CTextInput* pInput);
void onKeyboardFocus(wlr_surface*); void onKeyboardFocus(wlr_surface*);
STextInput* getFocusedTextInput(); CTextInput* getFocusedTextInput();
STextInput* getFocusableTextInput();
void setPendingSurface(STextInput*, wlr_surface*);
SIMEKbGrab* getIMEKeyboardGrab(SKeyboard*); SIMEKbGrab* getIMEKeyboardGrab(SKeyboard*);
void setIMEPopupFocus(SIMEPopup*, wlr_surface*); void setIMEPopupFocus(CInputPopup*, wlr_surface*);
void updateInputPopup(SIMEPopup*); void removePopup(CInputPopup*);
void damagePopup(SIMEPopup*);
void removePopup(SIMEPopup*); CInputPopup* popupFromCoords(const Vector2D& point);
CInputPopup* popupFromSurface(const wlr_surface* surface);
void updateAllPopups();
private: private:
std::unique_ptr<SIMEKbGrab> m_pKeyboardGrab; std::unique_ptr<SIMEKbGrab> m_pKeyboardGrab;
std::list<STextInput> m_lTextInputs; std::vector<std::unique_ptr<CTextInput>> m_vTextInputs;
std::list<SIMEPopup> m_lIMEPopups; std::vector<std::unique_ptr<CInputPopup>> m_vIMEPopups;
wlr_surface* m_pLastKbFocus = nullptr;
DYNLISTENER(textInputNew); DYNLISTENER(textInputNew);
DYNLISTENER(IMECommit); DYNLISTENER(IMECommit);
@@ -45,10 +53,9 @@ class CInputMethodRelay {
DYNLISTENER(IMEGrab); DYNLISTENER(IMEGrab);
DYNLISTENER(IMENewPopup); DYNLISTENER(IMENewPopup);
void createNewTextInput(wlr_text_input_v3*, STextInputV1* tiv1 = nullptr);
wlr_surface* focusedSurface(STextInput* pInput);
friend class CHyprRenderer; friend class CHyprRenderer;
friend class CInputManager; friend class CInputManager;
friend class CTextInputV1ProtocolManager; friend class CTextInputV1ProtocolManager;
friend struct CTextInput;
friend class CHyprRenderer;
}; };

View File

@@ -7,6 +7,8 @@ void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
static auto PSWIPEFINGERS = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_fingers"); static auto PSWIPEFINGERS = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_fingers");
static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new"); static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new");
EMIT_HOOK_EVENT_CANCELLABLE("swipeBegin", e);
if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked()) if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked())
return; return;
@@ -24,7 +26,7 @@ void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
} }
void CInputManager::beginWorkspaceSwipe() { void CInputManager::beginWorkspaceSwipe() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace); const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace;
Debug::log(LOG, "Starting a swipe from {}", PWORKSPACE->m_szName); Debug::log(LOG, "Starting a swipe from {}", PWORKSPACE->m_szName);
@@ -42,14 +44,18 @@ void CInputManager::beginWorkspaceSwipe() {
} }
void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) { void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
EMIT_HOOK_EVENT_CANCELLABLE("swipeEnd", e);
if (!m_sActiveSwipe.pWorkspaceBegin) if (!m_sActiveSwipe.pWorkspaceBegin)
return; // no valid swipe return; // no valid swipe
endWorkspaceSwipe();
}
void CInputManager::endWorkspaceSwipe() {
static auto PSWIPEPERC = CConfigValue<Hyprlang::FLOAT>("gestures:workspace_swipe_cancel_ratio"); static auto PSWIPEPERC = CConfigValue<Hyprlang::FLOAT>("gestures:workspace_swipe_cancel_ratio");
static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance"); static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance");
static auto PSWIPEFORC = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_min_speed_to_force"); static auto PSWIPEFORC = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_min_speed_to_force");
static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new"); static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new");
static auto PSWIPENUMBER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_numbered");
static auto PSWIPEUSER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_use_r"); static auto PSWIPEUSER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_use_r");
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
@@ -57,8 +63,8 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
// commit // commit
std::string wsname = ""; std::string wsname = "";
auto workspaceIDLeft = getWorkspaceIDFromString(*PSWIPENUMBER ? "-1" : (*PSWIPEUSER ? "r-1" : "m-1"), wsname); auto workspaceIDLeft = getWorkspaceIDFromString((*PSWIPEUSER ? "r-1" : "m-1"), wsname);
auto workspaceIDRight = getWorkspaceIDFromString(*PSWIPENUMBER ? "+1" : (*PSWIPEUSER ? "r+1" : "m+1"), wsname); auto workspaceIDRight = getWorkspaceIDFromString((*PSWIPEUSER ? "r+1" : "m+1"), wsname);
// If we've been swiping off the right end with PSWIPENEW enabled, there is // If we've been swiping off the right end with PSWIPENEW enabled, there is
// no workspace there yet, and we need to choose an ID for a new one now. // no workspace there yet, and we need to choose an ID for a new one now.
@@ -84,7 +90,7 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP; const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP;
const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP; const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP;
CWorkspace* pSwitchedTo = nullptr; PHLWORKSPACE pSwitchedTo = nullptr;
if ((abs(m_sActiveSwipe.delta) < *PSWIPEDIST * *PSWIPEPERC && (*PSWIPEFORC == 0 || (*PSWIPEFORC != 0 && m_sActiveSwipe.avgSpeed < *PSWIPEFORC))) || if ((abs(m_sActiveSwipe.delta) < *PSWIPEDIST * *PSWIPEPERC && (*PSWIPEFORC == 0 || (*PSWIPEFORC != 0 && m_sActiveSwipe.avgSpeed < *PSWIPEFORC))) ||
abs(m_sActiveSwipe.delta) < 2) { abs(m_sActiveSwipe.delta) < 2) {
@@ -192,16 +198,24 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
} }
void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) { void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
EMIT_HOOK_EVENT_CANCELLABLE("swipeUpdate", e);
if (!m_sActiveSwipe.pWorkspaceBegin) if (!m_sActiveSwipe.pWorkspaceBegin)
return; return;
static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance");
static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_invert"); static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_invert");
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
const double delta = m_sActiveSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx));
updateWorkspaceSwipe(delta);
}
void CInputManager::updateWorkspaceSwipe(double delta) {
static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance");
static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new"); static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new");
static auto PSWIPEDIRLOCK = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_direction_lock"); static auto PSWIPEDIRLOCK = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_direction_lock");
static auto PSWIPEDIRLOCKTHRESHOLD = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_direction_lock_threshold"); static auto PSWIPEDIRLOCKTHRESHOLD = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_direction_lock_threshold");
static auto PSWIPEFOREVER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_forever"); static auto PSWIPEFOREVER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_forever");
static auto PSWIPENUMBER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_numbered");
static auto PSWIPEUSER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_use_r"); static auto PSWIPEUSER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_use_r");
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
@@ -209,15 +223,15 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP; const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
const double d = m_sActiveSwipe.delta - delta;
m_sActiveSwipe.delta = delta;
m_sActiveSwipe.delta += VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx); m_sActiveSwipe.avgSpeed = (m_sActiveSwipe.avgSpeed * m_sActiveSwipe.speedPoints + abs(d)) / (m_sActiveSwipe.speedPoints + 1);
m_sActiveSwipe.avgSpeed = (m_sActiveSwipe.avgSpeed * m_sActiveSwipe.speedPoints + abs(e->dx)) / (m_sActiveSwipe.speedPoints + 1);
m_sActiveSwipe.speedPoints++; m_sActiveSwipe.speedPoints++;
std::string wsname = ""; std::string wsname = "";
auto workspaceIDLeft = getWorkspaceIDFromString(*PSWIPENUMBER ? "-1" : (*PSWIPEUSER ? "r-1" : "m-1"), wsname); auto workspaceIDLeft = getWorkspaceIDFromString((*PSWIPEUSER ? "r-1" : "m-1"), wsname);
auto workspaceIDRight = getWorkspaceIDFromString(*PSWIPENUMBER ? "+1" : (*PSWIPEUSER ? "r+1" : "m+1"), wsname); auto workspaceIDRight = getWorkspaceIDFromString((*PSWIPEUSER ? "r+1" : "m+1"), wsname);
if ((workspaceIDLeft == WORKSPACE_INVALID || workspaceIDRight == WORKSPACE_INVALID || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) && !*PSWIPENEW) { if ((workspaceIDLeft == WORKSPACE_INVALID || workspaceIDRight == WORKSPACE_INVALID || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) && !*PSWIPENEW) {
m_sActiveSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe m_sActiveSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe
@@ -248,7 +262,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
if (workspaceIDLeft > m_sActiveSwipe.pWorkspaceBegin->m_iID || !PWORKSPACE) { if (workspaceIDLeft > m_sActiveSwipe.pWorkspaceBegin->m_iID || !PWORKSPACE) {
if (*PSWIPENEW || *PSWIPENUMBER) { if (*PSWIPENEW) {
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
if (VERTANIMS) if (VERTANIMS)
@@ -288,7 +302,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight);
if (workspaceIDRight < m_sActiveSwipe.pWorkspaceBegin->m_iID || !PWORKSPACE) { if (workspaceIDRight < m_sActiveSwipe.pWorkspaceBegin->m_iID || !PWORKSPACE) {
if (*PSWIPENEW || *PSWIPENUMBER) { if (*PSWIPENEW) {
g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor);
if (VERTANIMS) if (VERTANIMS)

View File

@@ -39,7 +39,8 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
switch (EVENT->tool->type) { switch (EVENT->tool->type) {
case WLR_TABLET_TOOL_TYPE_MOUSE: case WLR_TABLET_TOOL_TYPE_MOUSE:
wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy); wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy);
g_pInputManager->refocus(); g_pInputManager->simulateMouseMovement();
g_pInputManager->focusTablet(PTAB, EVENT->tool, true);
g_pInputManager->m_tmrLastCursorMovement.reset(); g_pInputManager->m_tmrLastCursorMovement.reset();
break; break;
default: default:
@@ -50,10 +51,17 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
if (PTAB->relativeInput) if (PTAB->relativeInput)
wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy); wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy);
else else {
// Calculate transformations if active area is set
if (!PTAB->activeArea.empty()) {
x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x);
y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y);
}
wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y); wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y);
}
g_pInputManager->refocus(); g_pInputManager->simulateMouseMovement();
g_pInputManager->focusTablet(PTAB, EVENT->tool, true);
g_pInputManager->m_tmrLastCursorMovement.reset(); g_pInputManager->m_tmrLastCursorMovement.reset();
break; break;
} }
@@ -62,7 +70,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
// TODO: this might be wrong // TODO: this might be wrong
if (PTOOL->active) { if (PTOOL->active) {
g_pInputManager->refocus(); g_pInputManager->simulateMouseMovement();
g_pInputManager->focusTablet(PTAB, EVENT->tool, true); g_pInputManager->focusTablet(PTAB, EVENT->tool, true);
} }
@@ -105,7 +113,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
// TODO: this might be wrong // TODO: this might be wrong
if (EVENT->state == WLR_TABLET_TOOL_TIP_DOWN) { if (EVENT->state == WLR_TABLET_TOOL_TIP_DOWN) {
g_pInputManager->refocus(); g_pInputManager->simulateMouseMovement();
g_pInputManager->focusTablet(PTAB, EVENT->tool); g_pInputManager->focusTablet(PTAB, EVENT->tool);
wlr_send_tablet_v2_tablet_tool_down(PTOOL->wlrTabletToolV2); wlr_send_tablet_v2_tablet_tool_down(PTOOL->wlrTabletToolV2);
} else { } else {
@@ -146,7 +154,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
} else { } else {
PTOOL->active = true; PTOOL->active = true;
g_pInputManager->refocus(); g_pInputManager->simulateMouseMovement();
g_pInputManager->focusTablet(PTAB, EVENT->tool); g_pInputManager->focusTablet(PTAB, EVENT->tool);
} }
@@ -258,12 +266,12 @@ void CInputManager::focusTablet(STablet* pTab, wlr_tablet_tool* pTool, bool moti
if (const auto PWINDOW = g_pCompositor->m_pLastWindow; PWINDOW) { if (const auto PWINDOW = g_pCompositor->m_pLastWindow; PWINDOW) {
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal(); const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
if (PTOOL->pSurface != g_pCompositor->m_pLastFocus) if (PTOOL->pSurface != g_pInputManager->m_pLastMouseSurface)
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2); wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);
if (g_pCompositor->m_pLastFocus) { if (g_pInputManager->m_pLastMouseSurface) {
PTOOL->pSurface = g_pCompositor->m_pLastFocus; PTOOL->pSurface = g_pCompositor->m_pLastFocus;
wlr_tablet_v2_tablet_tool_notify_proximity_in(PTOOL->wlrTabletToolV2, pTab->wlrTabletV2, g_pCompositor->m_pLastFocus); wlr_tablet_v2_tablet_tool_notify_proximity_in(PTOOL->wlrTabletToolV2, pTab->wlrTabletV2, g_pInputManager->m_pLastMouseSurface);
} }
if (motion) { if (motion) {

View File

@@ -0,0 +1,279 @@
#include "TextInput.hpp"
#include "../../defines.hpp"
#include "InputManager.hpp"
#include "../../protocols/TextInputV1.hpp"
#include "../../Compositor.hpp"
CTextInput::CTextInput(STextInputV1* ti) : pV1Input(ti) {
ti->pTextInput = this;
initCallbacks();
}
CTextInput::CTextInput(wlr_text_input_v3* ti) : pWlrInput(ti) {
initCallbacks();
}
CTextInput::~CTextInput() {
if (pV1Input)
pV1Input->pTextInput = nullptr;
}
void CTextInput::tiV1Destroyed() {
pV1Input = nullptr;
g_pInputManager->m_sIMERelay.removeTextInput(this);
}
void CTextInput::initCallbacks() {
hyprListener_textInputEnable.initCallback(
isV3() ? &pWlrInput->events.enable : &pV1Input->sEnable, [this](void* owner, void* data) { onEnabled(); }, this, "textInput");
hyprListener_textInputCommit.initCallback(
isV3() ? &pWlrInput->events.commit : &pV1Input->sCommit, [this](void* owner, void* data) { onCommit(); }, this, "textInput");
hyprListener_textInputDisable.initCallback(
isV3() ? &pWlrInput->events.disable : &pV1Input->sDisable, [this](void* owner, void* data) { onDisabled(); }, this, "textInput");
hyprListener_textInputDestroy.initCallback(
isV3() ? &pWlrInput->events.destroy : &pV1Input->sDestroy,
[this](void* owner, void* data) {
if (pWlrInput && pWlrInput->current_enabled && focusedSurface())
g_pInputManager->m_sIMERelay.deactivateIME(this);
hyprListener_textInputCommit.removeCallback();
hyprListener_textInputDestroy.removeCallback();
hyprListener_textInputDisable.removeCallback();
hyprListener_textInputEnable.removeCallback();
hyprListener_surfaceDestroyed.removeCallback();
hyprListener_surfaceUnmapped.removeCallback();
g_pInputManager->m_sIMERelay.removeTextInput(this);
},
this, "textInput");
}
void CTextInput::onEnabled(wlr_surface* surfV1) {
Debug::log(LOG, "TI ENABLE");
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
// Debug::log(WARN, "Enabling TextInput on no IME!");
return;
}
// v1 only, map surface to PTI
if (!isV3()) {
wlr_surface* pSurface = surfV1;
if (g_pCompositor->m_pLastFocus != pSurface || !pV1Input->active)
return;
enter(pSurface);
}
g_pInputManager->m_sIMERelay.activateIME(this);
}
void CTextInput::onDisabled() {
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
// Debug::log(WARN, "Disabling TextInput on no IME!");
return;
}
if (!focusedSurface())
return;
if (!isV3())
leave();
hyprListener_surfaceDestroyed.removeCallback();
hyprListener_surfaceUnmapped.removeCallback();
g_pInputManager->m_sIMERelay.deactivateIME(this);
}
void CTextInput::onCommit() {
if (!g_pInputManager->m_sIMERelay.m_pWLRIME) {
// Debug::log(WARN, "Committing TextInput on no IME!");
return;
}
if (!(pWlrInput ? pWlrInput->current_enabled : pV1Input->active)) {
Debug::log(WARN, "Disabled TextInput commit?");
return;
}
g_pInputManager->m_sIMERelay.commitIMEState(this);
}
void CTextInput::setFocusedSurface(wlr_surface* pSurface) {
if (pSurface == pFocusedSurface)
return;
pFocusedSurface = pSurface;
hyprListener_surfaceUnmapped.removeCallback();
hyprListener_surfaceDestroyed.removeCallback();
if (!pSurface)
return;
hyprListener_surfaceUnmapped.initCallback(
&pSurface->events.unmap,
[this](void* owner, void* data) {
Debug::log(LOG, "Unmap TI owner1");
if (enterLocks)
enterLocks--;
pFocusedSurface = nullptr;
hyprListener_surfaceUnmapped.removeCallback();
hyprListener_surfaceDestroyed.removeCallback();
},
this, "CTextInput");
hyprListener_surfaceDestroyed.initCallback(
&pSurface->events.destroy,
[this](void* owner, void* data) {
Debug::log(LOG, "destroy TI owner1");
if (enterLocks)
enterLocks--;
pFocusedSurface = nullptr;
hyprListener_surfaceUnmapped.removeCallback();
hyprListener_surfaceDestroyed.removeCallback();
},
this, "CTextInput");
}
bool CTextInput::isV3() {
return pWlrInput;
}
void CTextInput::enter(wlr_surface* pSurface) {
if (!pSurface || !pSurface->mapped)
return;
if (pSurface == focusedSurface())
return;
if (focusedSurface()) {
leave();
setFocusedSurface(nullptr);
}
enterLocks++;
if (enterLocks != 1) {
Debug::log(ERR, "BUG THIS: TextInput has != 1 locks in enter");
leave();
enterLocks = 1;
}
if (pWlrInput)
wlr_text_input_v3_send_enter(pWlrInput, pSurface);
else {
zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->resource);
pV1Input->active = true;
}
setFocusedSurface(pSurface);
}
void CTextInput::leave() {
if (!focusedSurface())
return;
enterLocks--;
if (enterLocks != 0) {
Debug::log(ERR, "BUG THIS: TextInput has != 0 locks in leave");
enterLocks = 0;
}
if (pWlrInput && pWlrInput->focused_surface)
wlr_text_input_v3_send_leave(pWlrInput);
else if (focusedSurface() && pV1Input) {
zwp_text_input_v1_send_leave(pV1Input->resourceImpl);
pV1Input->active = false;
}
setFocusedSurface(nullptr);
g_pInputManager->m_sIMERelay.deactivateIME(this);
}
wlr_surface* CTextInput::focusedSurface() {
return pWlrInput ? pWlrInput->focused_surface : pFocusedSurface;
}
wl_client* CTextInput::client() {
return pWlrInput ? wl_resource_get_client(pWlrInput->resource) : pV1Input->client;
}
void CTextInput::commitStateToIME(wlr_input_method_v2* ime) {
if (isV3()) {
if (pWlrInput->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT)
wlr_input_method_v2_send_surrounding_text(ime, pWlrInput->current.surrounding.text, pWlrInput->current.surrounding.cursor, pWlrInput->current.surrounding.anchor);
wlr_input_method_v2_send_text_change_cause(ime, pWlrInput->current.text_change_cause);
if (pWlrInput->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE)
wlr_input_method_v2_send_content_type(ime, pWlrInput->current.content_type.hint, pWlrInput->current.content_type.purpose);
} else {
if (pV1Input->pendingSurrounding.isPending)
wlr_input_method_v2_send_surrounding_text(ime, pV1Input->pendingSurrounding.text.c_str(), pV1Input->pendingSurrounding.cursor, pV1Input->pendingSurrounding.anchor);
wlr_input_method_v2_send_text_change_cause(ime, 0);
if (pV1Input->pendingContentType.isPending)
wlr_input_method_v2_send_content_type(ime, pV1Input->pendingContentType.hint, pV1Input->pendingContentType.purpose);
}
g_pInputManager->m_sIMERelay.updateAllPopups();
wlr_input_method_v2_send_done(ime);
}
void CTextInput::updateIMEState(wlr_input_method_v2* ime) {
if (isV3()) {
if (ime->current.preedit.text) {
wlr_text_input_v3_send_preedit_string(pWlrInput, ime->current.preedit.text, ime->current.preedit.cursor_begin, ime->current.preedit.cursor_end);
}
if (ime->current.commit_text) {
wlr_text_input_v3_send_commit_string(pWlrInput, ime->current.commit_text);
}
if (ime->current.delete_.before_length || ime->current.delete_.after_length) {
wlr_text_input_v3_send_delete_surrounding_text(pWlrInput, ime->current.delete_.before_length, ime->current.delete_.after_length);
}
wlr_text_input_v3_send_done(pWlrInput);
} else {
if (ime->current.preedit.text) {
zwp_text_input_v1_send_preedit_cursor(pV1Input->resourceImpl, ime->current.preedit.cursor_begin);
zwp_text_input_v1_send_preedit_styling(pV1Input->resourceImpl, 0, std::string(ime->current.preedit.text).length(), ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT);
zwp_text_input_v1_send_preedit_string(pV1Input->resourceImpl, pV1Input->serial, ime->current.preedit.text, "");
} else {
zwp_text_input_v1_send_preedit_cursor(pV1Input->resourceImpl, ime->current.preedit.cursor_begin);
zwp_text_input_v1_send_preedit_styling(pV1Input->resourceImpl, 0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT);
zwp_text_input_v1_send_preedit_string(pV1Input->resourceImpl, pV1Input->serial, "", "");
}
if (ime->current.commit_text) {
zwp_text_input_v1_send_commit_string(pV1Input->resourceImpl, pV1Input->serial, ime->current.commit_text);
}
if (ime->current.delete_.before_length || ime->current.delete_.after_length) {
zwp_text_input_v1_send_delete_surrounding_text(pV1Input->resourceImpl, std::string(ime->current.preedit.text).length() - ime->current.delete_.before_length,
ime->current.delete_.after_length + ime->current.delete_.before_length);
if (ime->current.preedit.text)
zwp_text_input_v1_send_commit_string(pV1Input->resourceImpl, pV1Input->serial, ime->current.preedit.text);
}
}
}
bool CTextInput::hasCursorRectangle() {
return !isV3() || pWlrInput->current.features & WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE;
}
CBox CTextInput::cursorBox() {
return CBox{isV3() ? pWlrInput->current.cursor_rectangle : pV1Input->cursorRectangle};
}

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