Compare commits

..

344 Commits

Author SHA1 Message Date
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
Vaxry
19c90048d6 props: bump ver to 0.37.0 2024-03-15 23:58:39 +00:00
Vaxry
3f5f5f5491 splashes: add 2ya splash 2024-03-15 23:58:22 +00:00
Vaxry
2a2da6082e renderer: fix invalid access on non-assigned surfaces
fixes #5125
2024-03-15 21:29:20 +00:00
Vaxry
c4f52d1979 master: fix invalid config usage 2024-03-15 19:31:33 +00:00
Vaxry
38576d651a renderer: adjust surface dimensions for oversized not-yet ackd surface sizes
supersedes #5104
2024-03-15 19:23:51 +00:00
drendog
72d78eff95 sessionlock: refocus after destroy focused surface (#5117)
* fix: refocus after destroy focused surface

* refactor: minor refactor on refocus loop condition

* refactor: minor refactor on condition

* style: format code
2024-03-15 18:44:17 +00:00
Maximilian Seidler
a958884b52 lock: fix red screen issues with multiple monitors (#5100)
* lock: use uint64_t for iMonitorID

* lock: move activateLock to onNewSessionLock

* lock: add red screen fade

* lock: damage when fading the red screen and delay for screencopy

* lock: remove redundant scheduleFrameForMonitor
2024-03-15 16:17:13 +00:00
Vaxry
bb933dcf04 popup: avoid damage loops with commits
fixes #5118
2024-03-15 15:55:30 +00:00
thejch
bc15a8f600 renderer: Allow headless mode in hyprland (#4794)
* allow headless

* clang-format

* fix redundant logic lol
2024-03-15 14:28:14 +00:00
Mihai Fufezan
6c24cee88f flake.lock: update 2024-03-15 11:13:27 +02:00
Mihai Fufezan
d00c658405 Nix: add wrapping back
Ref: https://github.com/hyprwm/hyprland-plugins/issues/93
2024-03-15 10:11:56 +02:00
Vaxry
dc44bd7113 ci: remove codeql
bullshit, useless, and only fails for no reason
2024-03-15 03:32:24 +00:00
Vaxry
045c3fbd85 subsurface: fix visibility check
ref #5113
2024-03-14 20:42:33 +00:00
Vaxry
b7b13623ba subsurface/popup: expand on map/unmap to add buffering
ref #5113
2024-03-14 20:21:58 +00:00
Vaxry
164e92f8e3 internal: minor fixups for fading out xwayland windows
fixes #4935
2024-03-14 18:25:28 +00:00
Vaxry
3e67ee0f5f events: ignore setTitle when title didn't change 2024-03-13 15:38:24 +00:00
djvs
893c55217b input: only override dragging corner on floating (#5092)
Co-authored-by: djvs <djvs@users.noreply.github.com>
2024-03-13 03:38:32 +00:00
djvs
c58fcfbce2 input: add general:resize_corner for manual resizing (#5090)
* Resize corner config thing

* clang-format

---------

Co-authored-by: djvs <djvs@users.noreply.github.com>
2024-03-13 02:43:22 +00:00
thejch
7ea555da7f master: Fix master layout window focus and scroll (#5074)
* fix master switch window scrolling

* fix some more dispatchers and remove some duplicate code

* refactor and remove duplicate code

* fix focusmonitor: https://github.com/hyprwm/Hyprland/issues/5006#issuecomment-1986977255

* change check
2024-03-13 02:09:20 +00:00
Mihai Fufezan
6c53d4d82f Nix: remove hyprland-unwrapped leftover 2024-03-12 21:35:41 +02:00
Vaxry
5da9591775 config: more safety around monitor keyword
ref https://github.com/hyprwm/hyprland-wiki/issues/523
2024-03-12 15:37:46 +00:00
Ikko Eltociear Ashimine
f1ec0ba467 keybinds: Fix typo (#5081)
minor fix
2024-03-12 15:26:42 +00:00
Vaxry
a065b481f3 cursormgr: use XCURSOR_THEME for x themes 2024-03-11 20:33:26 +00:00
Lucas Reis
0fc9d45e4b core: Fix typo and check grandchild PID in spawn() (#5070) 2024-03-11 19:31:39 +00:00
Vaxry
66330281ff config: report errors from sourced files 2024-03-11 01:39:00 +00:00
Vaxry
220144276b layout: unfullscreen on toggle into tiled fullscreen
fixes a bug where the tiled window would be on top
2024-03-10 22:31:49 +00:00
Vaxry
0a1632a79f dwindle: preserve fs state on switchWindows
fixes #2842
2024-03-10 22:27:23 +00:00
NotAShelf
981296f101 flake: bump inputs (#5066) 2024-03-10 19:52:54 +00:00
Vaxry
0c28d4e334 window: prevent vector modification segfault while iterating
oops, updateWindow can modify the vec
2024-03-10 16:56:42 +00:00
Matt Wyatt
335506d555 constraints: only warp cursor on deactivate if constraint is locked. (#5056) 2024-03-09 23:19:48 +00:00
Vaxry
b0f98a3d3e compositor: reject focus to noFocus OR xwayland windows
fixes #4922
2024-03-09 22:39:23 +00:00
Vaxry
2ed032a7fd xwayland: fix no_xwayland compiles 2024-03-09 22:37:49 +00:00
Vaxry
739c5bc98c cursormgr: fix invalid access to hyprcursor in xwayland init
fixes #5048
2024-03-09 21:54:33 +00:00
Vaxry
26cd1bf949 input: fix minor default cursor reset conditions 2024-03-09 18:12:55 +00:00
Vaxry
18a35b1406 cursormgr: fix memory leak with cursor buffers 2024-03-09 18:04:33 +00:00
Vaxry
7e41e5146d cursormgr: add fallbacks for unknown cursors 2024-03-09 18:00:37 +00:00
Vaxry
c3882bb832 internal: Support libhyprcursor (#5009)
woo

---------

Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
2024-03-09 16:52:59 +00:00
Vaxry
e7a5db4852 xwayland: Set xwayland's name prop (#4924)
* set xwayland name

* [gha] Nix: update wlroots

* fix

---------

Co-authored-by: vaxerski <vaxerski@users.noreply.github.com>
2024-03-09 16:47:57 +00:00
Vaxry
a01949dd28 deco: fix warnings 2024-03-09 16:39:38 +00:00
vaxerski
fa886d8b11 [gha] Nix: update wlroots 2024-03-09 16:36:19 +00:00
Vaxry
3f58e77e75 deps: update wlroots 2024-03-09 16:35:35 +00:00
Vaxry
300d77edd9 keybinds: track submap at press for keypresses
fixes #5037
2024-03-09 16:08:07 +00:00
Vaxry
c9ea600baa layer-shell: allow for popup creation before map
ref https://github.com/jjsullivan5196/wvkbd/issues/65
2024-03-09 15:32:36 +00:00
Vaxry
3e930a568a format: fix format 2024-03-09 03:09:25 +00:00
Vaxry
024d4ddc74 input: scale local coords in constraints
fixes #5029
2024-03-08 22:51:28 +00:00
Vaxry
717d5b3cc2 hyprctl: hide unmapped windows without -a 2024-03-08 17:47:12 +00:00
Vaxry
0a4ade01d3 format: make ci happy 2024-03-08 17:40:28 +00:00
Aaron
5920c6a6b8 socket2: Add 5 IPC event with support for workspace ID (#5022)
- `moveworkspacev2`:    returns workspaceID,workspaceName,monitorName
- `movewindowv2`:       returns windowAddress,workspaceID,workspaceName
- `createWorkspacev2`:  returns workspaceID,workspaceName
- `destroyWorkspacev2`: returns workspaceID,workspaceName
- `workspacev2`:        returns workspaceID,workspaceName

- Include workspaceID as a parameter in CWorkspace constructor to support `createWorkspacev2`.

Resolves #4929
2024-03-08 17:39:53 +00:00
Vaxry
4c34e4aac2 windowrules: minor improvements to min/max size
fixes #5017
2024-03-08 17:10:38 +00:00
Fazzi
d1c80c31c8 README: change dwl link to new codeberg link (#5026) 2024-03-08 16:30:42 +00:00
Epilepsy Gatherings
1290507ac4 windowrules: check if floating when resizing from maxsize (#5019)
* check if floating

* use return
2024-03-08 14:54:45 +00:00
Epilepsy Gatherings
e52d3fa852 windowrules: Make min/maxsize rules dynamic (#4775)
* rebase

* simplify and remove prop

* Stuff

- add back win prop
- change minsize defaults
- change request formatting for setprop

* style fix

* remove empty line

* change defaults

* redo string to vec

* remove redundant parsing

* change to vec

* support commas

* remove static rules

* take out garbage

* format

* don't allow commas and resize on setprop

* use isNumber
2024-03-08 02:24:44 +00:00
ItsDrike
ceecdd0fd5 hyprctl: Fix incorrect invalid fontsize kwarg response (#5013) 2024-03-07 23:34:33 +00:00
thejch
6c4e2489a0 layout: Fix toggling fullscreen special workspace on different monitor (#5000)
* fix toggling fullscreen special ws on different monitor

* add for dwindle

* fix change regular workspace when special fullscreen
2024-03-07 13:27:58 +00:00
thejch
bf71026b8d master: change active monitor when moving windows around (#5001) 2024-03-07 13:23:22 +00:00
Mihai Fufezan
77161fdbef flake.lock: update 2024-03-07 11:03:43 +02:00
Mihai Fufezan
ce072638e9 Nix: use propagatedBuildInputs instead of wrapping
This way, users that want to wrap Hyprland themselves won't have the
issues of double-wrapping.
2024-03-07 11:02:18 +02:00
Vaxry
95769a3c54 compositor: update state after moving to workspace
fixes #4987
2024-03-06 21:33:55 +00:00
ItsDrike
067df84388 notify: Add custom fontsize support for notifications (#4981)
* Add custom fontsize support for notifications

* Remove debug stuff

* Use original default font size

* Handle fontsize as keyword arg

* Use CVarList::join instead of for loop

* Use size_t for msgidx
2024-03-06 21:20:26 +00:00
Vaxry
8e2a62e53b events: apply monitor state on sessionActive
ref #4839
2024-03-06 18:14:59 +00:00
Vaxry
669ea8a373 ci: pack hyprpm to the release tar 2024-03-06 15:26:58 +00:00
ItsDrike
082bf00254 hyprpm: Add support for specifying exact git revisions for plugin repo (#4983)
* hyprpm(feat): support specifying exact git revs

* Mention git rev argument in help

* Mention git rev arg is optional

* Wrap text
2024-03-06 12:01:04 +00:00
outfoxxed
d6f1b151b2 animations: fix m_Goal not being set after #4911 (#4992) 2024-03-06 10:14:13 +00:00
bvr-yr
fb87e332c5 input: fix window move stutter by introducing additional checks for low-hz monitors (#4553)
* resize-limiter: add additional check for low-hz monitors

* simplify checker

* add comment

* rename variable
2024-03-06 00:15:44 +00:00
Zach DeCook
b1e2ca04a0 CrashReporter: Fix compilation with musl libc (#4805)
It can be assumed this doesn't function correctly:
my 'configuration does not support execinfo.h', so I have no backtrace to test against
2024-03-05 22:51:34 +00:00
Vaxry
05dd204c5f window: ignore surface updates in unsafe / on invalid monitors 2024-03-05 20:46:08 +00:00
Vaxry
31e1287da2 subsurface: don't update transform on unmap
fixes #4969
2024-03-05 20:45:23 +00:00
Vaxry
a4c1f4a03d popup: send scale on map
fixes #4972
2024-03-05 20:42:29 +00:00
Grant Ammons
0ee69058c4 config: Add input:scroll_factor configuration (#4980)
* Allow for input:scroll_factor configuration

This PR will allow for a `scroll_factor` configuration within an `input`
block.  The purpose is to control the scroll factor of external mice.

Closes #2574.

* clang-format
2024-03-05 19:18:53 +00:00
Junxuan Liao
f8a081b56d layout: warp the cursor when focusing windows (#4982)
Similar to the `focuswindow` dispatcher, when focusing a window with
wlr-foreign-toplevel-management, the cursor should be warped. Otherwise, the
focus is lost immediately after the cursor moves.
2024-03-05 17:56:06 +00:00
Vaxry
bdfa8ab856 hyprctl: print format and modes
fixes #4971
2024-03-05 13:55:38 +00:00
Junxuan Liao
08152477dc monitor: remove commas from short description (#4970)
Since `hyprctl monitor` shows szShortDescription now, it needs to be sanitized.
(See #2457)

Also, monitor selectors are now compared against szShortDescription and
szDescription to avoid re-striping the string.
2024-03-05 13:41:51 +00:00
Vaxry
12985fa0d8 surface: fix damage tearing feedback
fixes #4935
2024-03-05 00:21:37 +00:00
thejch
9c48c322d4 keybinds: Allow fullscreen/maximize in special workspace (#4921)
* allow fullscreen/maximize in special workspace

* remove duplicate code

* hide top layer

* fix special fullscreen deco

* edit

* fix fade top layer when toggle special

* remove double render
2024-03-04 23:29:45 +00:00
Vaxry
7a76ab01d1 input: send motion to confined cursors 2024-03-04 23:07:16 +00:00
musjj
f3c92e75c8 CI/Nix: attempt to fix broken cache (#4963)
DeterminateSystems/nix-installer-action is causing hash inconsistency between CI & local build.
2024-03-04 20:33:42 +02:00
Tom Benham
07c7235b72 keybinds: Better handling of workspace_back_and_forth (#4952)
* Removed redundant boolean condition

* Better handling of workspace_back_and_forth when using focusworkspaceoncurrentmonitor dispatcher

* Fixed config acquisition

---------

Co-authored-by: Tom Benham <tom.benham@quadrille.fr>
2024-03-04 17:05:20 +00:00
Vaxry
12da0fc84f hyprctl: parse custom types in getoption 2024-03-04 10:36:38 +00:00
Isaiah Hamilton
9d89b7109d config: update per device input configs link (#4951) 2024-03-03 23:00:28 +00:00
Vaxry
063708df26 config: improve config value infrastructure 2024-03-03 18:41:38 +00:00
JManch
8ccbd272cc compositor: ignore grab extend behind special workspaces (#4944)
* compositor: ignore grab extend behind special workspaces

* ignore the window entirely
2024-03-03 17:04:39 +00:00
thejch
28272d2d74 master: Fix animate resize (#4942)
* fix master animate resize

* fix some other pointers
2024-03-03 17:03:23 +00:00
Vaxry
c701767038 xkb: handle invalid keymaps in updateXKBTranslationState
fixes #4941
2024-03-03 17:02:15 +00:00
Vaxry
cc94123fa7 renderer: minor fixes to transformations 2024-03-03 02:18:06 +00:00
Julien Roy
2a08f2ba84 opengl: fix compilation on legacy renderer (#4928) 2024-03-03 00:31:36 +00:00
Vaxry
689fced8b9 windowrules: fix center
fixes #4934
2024-03-03 00:22:40 +00:00
Epilepsy Gatherings
acf0b536a6 xwayland: disable initial focus for xwayland dialogs (#4936) 2024-03-03 00:18:53 +00:00
JManch
1762e9c6ec renderer: respect forceNoBlur when rendering small surface windows (#4932) 2024-03-03 00:17:40 +00:00
Tobias Zimmermann
964f1a438d keybinds: Add the 'catchall' keyword that matches all keys (#4930)
* Add the 'catchall' keyword that matches all keys

This keyword can be used to define arbitrary keybinds. The only special
behavior that it exhibits is that it matches every key, including
modifier keys. Any flags still apply normally.

This commit also fixes an issue that keys bound via the code:KEYCODE
format were not unbound correctly.

* Disallow catchall keybinds outside of submaps

A catchall keybind outside a submap would prevent essentially all key
events from going through to applications and would be difficult to
remove again.
2024-03-03 00:17:02 +00:00
JManch
508262b7db events: update render data after workspace window rule (#4931) 2024-03-02 22:15:07 +00:00
Vaxry
d72ea5f2a7 input: Rewritten pointer constraints (#4889)
* rewritten constraints

* send pointer enter on activate if not pointer focus

* minor cleanup

* simulate movement on commit

* don't ignore oneshot prop

* various fixes

* dont send motion on confined

* update pos hint on region change
2024-03-02 21:04:55 +00:00
Vaxry
328ab43165 hyprpm: don't copy .so if file doesn't exist
ref #4926
2024-03-02 19:06:09 +00:00
Vaxry
d2289d8327 xdg: minor improvements to initial size reporting
fixes #4918
2024-03-02 18:53:17 +00:00
ItsDrike
be89d6faa9 notifs: Implement notification dimissing (#4790) 2024-03-02 18:12:31 +00:00
Vaxry
8811f4b69a drag: check min size for reisze drags
fixes #4920
2024-03-02 15:25:32 +00:00
Vaxry
52db216608 events: don't switch to active workspace on workspace rule 2024-03-02 15:20:40 +00:00
ves
1e311c947e Nix: add missing dependencies for make asan (#4919) 2024-03-02 17:02:33 +02:00
Vaxry
7ce781e87c keybinds: better follow xkb translation state
fixes #4908
2024-03-02 01:46:55 +00:00
GartoxFR
b2c3440477 animations: Refactor AnimatedVariable (#4911)
* animation: Refactor AnimatedVariable

This commit decomposes the AnimatedVariable class into a base class
with the common attribute to all variable types and a templated derived
type containing strongly typed info on the type being animated.

Access to the typed version is perfomed using the visitor pattern. A
utility is provided to build a visitor on the fly using lambdas.

Adding a new type to be animated should just be a matter of adding the
typed in the list defined by the ANIMABLE_TYPES macro

The size of the commit is justified by the API change in the
AnimatedVariable class. No more vec(), fl() or col() method but a unified
value() method.

* animation: Remove visitor pattern

* animation: Fix coding style

* animation: Fix coding style
2024-03-02 00:35:17 +00:00
Vaxry
f115ba94d2 xwayland: set scaledBy for unmanaged windows in map 2024-03-01 23:04:34 +00:00
Brett Alcox
6e3a494d1d core: add additional headers for Popup.cpp and InputMethodRelay.hpp (#4909) 2024-03-01 20:07:36 +00:00
Vaxry
555afea73c makefile: add config to make asan 2024-03-01 14:16:56 +00:00
Vaxry
4937352761 makefile: add asan 2024-03-01 14:14:28 +00:00
Vaxry
f590505daf popup: minor fixes to xdg geometries
fixes #4900
2024-02-29 21:51:50 +00:00
Vaxry
f801d15947 configmgr: fix compile on 32-bit archs
fixes #4895
2024-02-29 21:33:39 +00:00
Vaxry
e63b4b18aa renderer: force a few render frames on init anim end
fixes #4875
2024-02-29 19:04:40 +00:00
Vaxry
1698d336f2 core: fix crashes on access of deleted wlr_ surface
ref fixes #4893
2024-02-29 17:23:44 +00:00
Vaxry
fbba8757cb window: remove unused list 2024-02-29 16:16:03 +00:00
Vaxry
6916d0a6a3 surface: unify owners 2024-02-29 15:07:14 +00:00
Anton Samokhvalov
bcec082a1c build: fix libc++/clang build (#4886) 2024-02-29 15:01:56 +00:00
Vaxry
2e111c8cf9 xdg: rewrite entire popup implementation 2024-02-29 14:26:02 +00:00
Vaxry
b39dcfa497 refactor: move a few things to desktop/ 2024-02-29 13:03:38 +00:00
Vaxry
4bff762d97 xwaylandmgr: don't read xwayland surface from unmapped xwayland 2024-02-29 01:21:23 +00:00
Vaxry
b1c0f1cc01 subsurface: Rewrite the subsurface tree (#4877) 2024-02-29 00:03:28 +00:00
Vaxry
1e7eb3a5a5 xdg: check for floating conditions before sending tiled size hint
ref #4871
2024-02-28 23:14:50 +00:00
Vaxry
097f561e41 surfacetree: Revert "subsurfaceTree: assign surfaces to a CWLSurface"
This reverts commit 51b1b17fcb.

Crash issues, fixes #4874
2024-02-28 19:42:04 +00:00
Vaxry
a31433c215 renderer: damage whole ring on failed commit
fixes #4770
2024-02-28 18:00:02 +00:00
Vaxry
51b1b17fcb subsurfaceTree: assign surfaces to a CWLSurface
fixes #4872
2024-02-28 17:53:17 +00:00
Vaxry
29cdd7de1f layers: minor fixes for new animations 2024-02-28 15:59:45 +00:00
Vaxry
4bc669f933 layers: add fully featured animations
Adds configs and layerrules to handle them

alas fixes #981

I have cooked
2024-02-28 15:00:40 +00:00
vaxerski
f4f3aa2e50 layout: add size prediction for initial xdg commits
fixes #4022
2024-02-28 11:45:43 +00:00
JManch
c198d744b7 keybinds: unconstrain mouse on focusmonitor and cyclenext (#4863) 2024-02-28 00:52:45 +00:00
Vaxry
1c460e98f8 props: bump ver to 0.36.0 2024-02-28 00:32:40 +00:00
Tobias Zimmermann
489ac40abd config: Add option to resolve keybinds by sym instead of code (#4851)
This commit adds the new configuration option 'resolve_binds_by_sym'
which can be set globally or per-device. It is off by default, which
preserves the current behavior.

This setting only affects the behavior of keybinds that are defined via
key symbols, not those defined via keycode. Binds defined by symbols
currently activate if the keycode pressed would generate the specified
symbol on the first layout specified in the input section.
If enabled, keys pressed on the relevant device will instead match
keybinds by the symbols they produce with their current layout.

Closes #1881.
2024-02-27 23:21:22 +00:00
Vaxry
e3373669e5 wayland: implement keyboard_shortcuts_inhibit_v1
fixes #4568
2024-02-27 23:15:24 +00:00
Vaxry
f26d7aa58d config: add defaultName for workspace rules
alas, fixes #665
2024-02-27 22:44:42 +00:00
Vaxry
e2c286548d avar: return curve value of 1 when not animated
fixes #4862
2024-02-27 22:34:07 +00:00
Philip Damianik
60f81b8a23 input: Map touch devices and tablets bound to an output (#3544)
* Map bound touch devices and tablets to an output

* Add "[[Auto]]" default option for auto detecting outputs for touch inputs

* Bind new monitors to configured touch and tablet devices

* Use Monitor::matchesStaticSelector in CConfigManager::getMonitorRuleFor

* Use Monitor::matchesStaticSelector in CCompositor::getMonitorFromString
2024-02-27 22:11:59 +00:00
vaxerski
98034fea3c screencopy: send full frame damage
fixes #4855
2024-02-27 14:51:27 +00:00
Vaxry
21f7f32dc9 screencopy: avoid dangling client ptrs on client destroy 2024-02-27 12:23:59 +00:00
Vaxry
ffd7217243 IME: don't set modifiers on grab destroy 2024-02-27 12:23:45 +00:00
Vaxry
bc3f5b94eb core: nullcheck for old monitor in moveWorkspaceToMonitor
fixes #4495
2024-02-26 21:12:12 +00:00
Vaxry
f7a3453487 socket2: move to the wayland event loop 2024-02-26 17:20:51 +00:00
Bernd Müller
1742605eb8 keybinds: fix movewindoworgroup onto empy workspace on next monitor (#4486)
* fix: movewindoworgroup when no window or group is in desired direction, e.g. move window onto empty workspace on next monitor

* fix: movewindoworgroup when no window or group is in desired direction, e.g. move window onto empty workspace on next monitor

* reset flake.nix

* add: changes mentioned in review of #4486
2024-02-26 14:05:24 +00:00
github-usr-name
81fe2ae7f1 surface: ensure global pointers valid before using in destructor (#4844)
This fixes an observed SigSegV resulting from the cursor surface using
`g_pInputManager` when invoked from the `CInputManager` destructor

Co-authored-by: github-user-name <spam-here@github.com>
2024-02-26 09:52:12 +00:00
Vaxry
dfcfb92ec6 renderer: take into account fading out windows in solitary recheck 2024-02-26 00:19:16 +00:00
Vaxry
9815402074 keybinds: focus floating on top of fs 2024-02-26 00:15:59 +00:00
shezdy
a14f6b570f keybinds: fix focuswindow for fullscreen (#4840)
* focuswindow fix

* fix format

---------

Co-authored-by: ddmetz <77217897+ddmetz@users.noreply.github.com>
2024-02-26 00:05:20 +00:00
fufexan
7f35bff720 [gha] Nix: update inputs 2024-02-26 00:03:49 +00:00
Tom Benham
54a8329936 layout: Fixed ghost window when opened while fullscreen on a different workspace (#4822)
* Fixed ghost window when opened while fullscreen on a different workspace

* Format

---------

Co-authored-by: Tom Benham <tom.benham@quadrille.fr>
2024-02-25 14:09:41 +00:00
github-usr-name
f9cfec8abb compositor: allow source monitor to be provided to getMonitorInDirection (#4837)
Co-authored-by: github-user-name <spam-here@github.com>
2024-02-25 14:03:00 +00:00
Sergei Trofimovich
f534ac3fc4 hyprctl: add missing newline in error case of missing HYPRLAND_INSTANCE_SIGNATURE (#4832)
Before the change running a `hyprctl` in incomplete `Hyprland`
environment merged error message and prompt for me as:

    $ hyprctl activewindow
    HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)$

(note trailing `$` prompt).

After the change the newline is present as expected:

    $ hyprctl activewindow
    HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)
    $
2024-02-24 23:35:36 +00:00
Vaxry
9103af317e hyprctl: ignore non-lock files for instances 2024-02-24 23:35:18 +00:00
Vaxry
5824b0f305 hyprctl: fix showing invalid instances 2024-02-24 17:36:43 +00:00
JManch
e9528fc214 config: fix layout invalidation for keyword commands (#4826) 2024-02-24 14:06:28 +00:00
Vaxry
6f83856025 hyprctl: add -r argument 2024-02-24 14:02:03 +00:00
thejch
d92da7959a core: Fix SEGV/ABRT core dump when exiting (#4823)
* reset input manager first

* move reset
2024-02-24 02:50:54 +00:00
Mihai Fufezan
f27054c13e flake.nix: override inputs for xdph and hyprlang 2024-02-24 00:48:11 +02:00
Vaxry
bdbd8d965d hyprctl: jsonify new gaps
fixes #4820
2024-02-23 21:25:04 +00:00
Vaxry
bfb1e876a8 config: add opengl:force_introspection
fixes #4819
2024-02-23 21:21:24 +00:00
Vaxry
ca59bd5739 opengl: check bottom/bg layers for required introspection
ref #4818
2024-02-23 21:09:47 +00:00
thejch
f389f77015 core: Try to fix the exit hang (#4811)
* add signal removal

* use a flag instead

* remove signals in cleanup
2024-02-23 16:48:27 +00:00
Vaxry
8c3613632a renderer: nuke lastFrameDamage and rework finalDamage
this fucking SUCKED
2024-02-23 01:02:32 +00:00
Vaxry
c1ef361e02 renderer: fix logs 2024-02-23 00:02:48 +00:00
Vaxry
35e80a64a6 renderer: add more logging for fails in beginRender 2024-02-22 23:50:56 +00:00
Vaxry
e83bf4f7b7 core: add env to disable crash reporter 2024-02-22 23:10:59 +00:00
Vaxry
c353b7c4f7 renderer: minor fixes for introspection detection 2024-02-22 23:01:22 +00:00
Vaxry
d9757b61bf xdg: manually schedule initial configures
chasing wlroots

fixes #4801
2024-02-22 17:33:23 +00:00
vaxerski
28410922da [gha] Nix: update wlroots 2024-02-22 16:23:35 +00:00
Vaxry
cfc652e17d deps: downgrade wlroots due to xwayland segfaults 2024-02-22 16:22:51 +00:00
vaxerski
dbccbabac5 [gha] Nix: update wlroots 2024-02-22 15:56:22 +00:00
Vaxry
9a6956fe67 deps: update wlroots 2024-02-22 15:55:33 +00:00
Vaxry
af0c8e299b input: fix vectorToWindowUnified with floating over fs
fixes #4800
2024-02-22 15:42:17 +00:00
Vaxry
7fbe016c15 animationmgr: expand layer box for damage 2024-02-22 15:34:18 +00:00
Vaxry
0ebee80bca config: adjust default splash col 2024-02-22 15:28:58 +00:00
Vaxry
c4283abb9f compositor: check for pworkspace validity in setActiveMonitor 2024-02-22 15:12:51 +00:00
Vaxry
94aeb06d6b toplevelexport: set last damage for dmabuf copy 2024-02-22 03:10:01 +00:00
Vaxry
ea3fd13e24 shadow: fix missed invalid use of cfg val ptr
fixes #4785
2024-02-21 19:26:21 +00:00
Hiram Muñoz
dad8ffd576 renderer: Update splash text properties to be configurable (#4707)
* Update splash text properties to be configurable

The splash text's font and color properties have been updated to be configurable. This change includes adding new configuration values for the splash screen color and font. The rendering of the splash screen is also adjusted to use these new config values, allowing for easy customization of the splash text appearance.

* Updated to use Hyprlang config manager
2024-02-21 18:31:29 +00:00
q234rty
fc5ca391ad core: Fix building plugins (#4783) 2024-02-21 16:57:44 +00:00
André Silva
e5eb1bdf01 renderer: ignore set cursor surface if cursor should be hidden (#4780) 2024-02-21 13:48:48 +00:00
Dashie
ddf022d61c feat: Add css style gaps (#4723) 2024-02-21 11:07:39 +00:00
Vaxry
13d9854897 xdgpopup: fix UAF because of an invalid listener connection
destroy should be connected to popup::destroy, not popup::surface::destroy...

ref #4751
2024-02-20 18:14:36 +00:00
vaxerski
cd73dda16e sessionLock: send preferred fractional scale 2024-02-20 16:13:01 +00:00
vaxerski
02c9a2d769 screencopy: damage entire screen on a no-damage request 2024-02-20 15:22:54 +00:00
vaxerski
7ea37c9dc9 surface: fix damage calcs with a viewport src 2024-02-20 15:21:30 +00:00
Vaxry
86be75dd97 events: bring back accidentally nuked preConfigReload 2024-02-20 03:24:15 +00:00
thejch
030ed27cc8 crashreporter: Use ~/.cache as cache dir (#4719)
* use ~/.cache for crash reports

* minor word edit

* clang-format

* minor typo
2024-02-20 00:55:04 +00:00
Vaxry
e793f10b8b screencopy: fix invalid damage being used for final copy in dma 2024-02-19 20:05:51 +00:00
Vaxry
d62e7a5125 renderer: fixup damage_ring rotation 2024-02-19 19:11:05 +00:00
Vaxry
fe9c8d8745 format: fix formatting 2024-02-19 17:20:39 +00:00
vaxerski
df82625206 hyprctl: reload everything on dynamic source keywords 2024-02-19 12:45:05 +00:00
vaxerski
1763566308 surface: minor fixes for last logicalDamage calc fix 2024-02-19 11:34:55 +00:00
vaxerski
e4790e3f8e surface: fix invalid damage tracking in damageSurface
ref #4744
2024-02-19 11:24:54 +00:00
rszyma
69a4f08dbe keybinds: fix keys without keysyms triggering random binds (#4739) 2024-02-19 00:02:03 +00:00
Vaxry
c6b1d82c70 hyprctl: more safety around stoull 2024-02-18 23:31:43 +00:00
Vaxry
301b48b740 renderer: fix invalid damage accumulation with invalid buffer_age
fixes #4670
2024-02-18 16:04:08 +00:00
Vaxry
fae47ef462 config: fix errors in default config 2024-02-18 15:34:43 +00:00
Vaxry
5fc0b772c7 config: update default config for hyprlang migration 2024-02-18 15:02:34 +00:00
Vaxry
13f6f0b923 Migrate the config to hyprlang (#4656)
* Migrate to hyprlang

* pop up errors

* fix swapped args

* Meson & Nix: build with hyprlang

* CI: add hyprlang to setup action

* add infra for plugin stuff

* fix hyprctl getoption

* fix hyprctl getoption with json

* format

* fix post parse logic

* fix autogen config

* oops missed exec-once

* fmt

* fix ws rules

* require 0.3.0 for hyprlang

* nix: flaek

* minor type fixes

* fix cfg usages in swipe

* use cvarlist for ws rules

* fix throw in addPluginConfigVar

* Nix: update hyprlang

* minor fixes

* fix disableLogs

* mention hyprlang docs

* bump hyprlang dep in cmake

* Meson: bump min hyprlang version

Nix: update hyprlang

* minor fix

* Nix: update meson patch

---------

Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
2024-02-18 15:00:34 +00:00
Alessio Molinari
7e8bcd675d monitors: fix outputmgr nullptr crash (#4738) 2024-02-18 02:24:01 +00:00
Vaxry
683a4b07c5 rules: ignore static tile/float rules in dynamic gets
fixes #4736
2024-02-18 00:13:43 +00:00
Federico Maria Morrone
5261a8df81 keybinds: Add an option to pass a window argument to moveoutofgroup (#4724)
* keybinds: allow passing window to moveoutofgroup

* keybinds: cleaner handling of certain args
2024-02-17 22:44:22 +00:00
epicgamer256705
289d952a6e dispatchers: add Fullscreen without sending fullscreen to application (#4720)
* Add extra option to fullscreen

* Remove useless branch

fixes #1817

---------

Co-authored-by: matteo bob <matteo4375@gmail.com>
2024-02-17 16:21:06 +00:00
Vaxry
294e51a857 input: refocus on completed drags 2024-02-17 16:02:17 +00:00
Vaxry
cdcc5aba06 xwayland: ignore OR activate requests if surface doesn't want focus 2024-02-17 02:47:07 +00:00
Abílio Costa
e3e7e1fdda monitor: don't damage twice (#4727)
When scaled, the ring is already fully damaged, no need to add the region
damage.

Also moved a variable that was being declared way to far for where it is
actually used.

Co-authored-by: Abilio Costa <abilio.costa@criticaltechworks.com>
2024-02-17 02:09:12 +00:00
Vaxry
fbf5ba87ce shaders: use highp for fragments 2024-02-15 17:32:34 +00:00
Jacob Birkett
a8dae8f5e1 socket2: monitoraddedv2 IPC event for monitor description and id (#4646)
* add monitor szShortDescription without DRM node name

* change hyprctl to use szShortDescription

* add monitoraddedv2 event

* add monitor ID as first param of monitoraddedv2
2024-02-15 14:22:20 +00:00
Vaxry
a42b984f51 screencopy: fix ~dtor being in monitorRenderResources map 2024-02-15 02:01:40 +00:00
Vaxry
e5ac970d6e input: fix follow_focus 2024-02-15 01:51:01 +00:00
Vaxry
770956b092 input: don't schedule frame on cursor move on hw cursors
spams unnecessary frames. Maybe we should ignore empty damage frame requests too?

ref #3747 #3490
2024-02-15 01:26:48 +00:00
Vaxry
3cca36e773 input: avoid rampant refocuses on popups 2024-02-15 01:24:40 +00:00
Vaxry
ef490965a2 screencopy: attempt binding framebuffer before gathering format 2024-02-15 00:59:06 +00:00
Vaxry
b7ab15dc80 input: log cursor image requests 2024-02-15 00:59:04 +00:00
Vaxry
9c3f3b0018 renderer: don't calculate mirror damage without mirrors present 2024-02-14 22:33:50 +00:00
Vaxry
8d68d6bfa5 windowrules: nuke no*request 2024-02-14 22:27:53 +00:00
Vaxry
60834a4687 config: remove usages of nomaximizerequest from default cfg 2024-02-14 22:26:45 +00:00
Vaxry
7f52db806c windowrules: add suppressevent
deprecates nofullscreenrequest nomaximizerequest
2024-02-14 22:19:49 +00:00
Vaxry
305b1419c8 renderer: accept custom state requests for fake outputs 2024-02-14 22:05:41 +00:00
Niklas Haas
d5950f7719 dwindle: add swapsplit dispatcher (#4702)
This is distinct from `swapwindow` in that it allows swapping the entire
tree node with its neighbour.

Fixes: https://github.com/hyprwm/Hyprland/issues/4701
2024-02-14 17:58:28 +00:00
vaxerski
0608791480 dwindle: round wbox before setting 2024-02-14 11:44:47 +00:00
vaxerski
2a002f31e4 renderer: don't set solitary on present notifications
fixes #4647
2024-02-14 11:09:18 +00:00
Epilepsy Gatherings
2a3429d4cf internal: add forcenofocus prop (#4672)
* add forcenofocus

* change nofocus to overridable var
2024-02-13 18:07:19 +00:00
Vaxry
95abf1220f keybinds: fix swapactiveworkspaces not moving focus
fixes #4626
2024-02-13 17:53:50 +00:00
Vaxry
b500e5699b renderer: update cursor also when hostpot only changes
fixes #4691
2024-02-13 17:39:51 +00:00
Filipe Paniguel
61378380ee config: fix tiny typo in defaultConfig.hpp (#4693) 2024-02-13 17:30:17 +00:00
Vaxry
890307532c input: avoid reassigns of unchanged surfaces in processMouseRequest 2024-02-12 20:02:00 +00:00
GrizzlT
f33d73b9cf nix: overlay polish for prev parameter (#4558) 2024-02-12 19:11:08 +02:00
ComycSans
927da86e3e hyprctl: fix dispatchBatch() treating empty curitem as last request (#4681) 2024-02-12 15:16:00 +00:00
Alessio Molinari
cca3c64301 hyprctl: remove hardcoded hyprctl commands. (#4671)
* fix: remove hardcoded hyprctl commands.

This allows plugin to properly register hyprctl commands.

* fix: restore commands with min args
2024-02-12 10:34:21 +00:00
fufexan
6e5c78bf63 [gha] Nix: update inputs 2024-02-12 00:03:37 +00:00
Vaxry
e4bb5fa4af input: focus monitor on mouse down
fixes #4649
2024-02-10 17:39:53 +00:00
Vaxry
cb258c82f4 assets: update tetrahedra by honkadaloonga 2024-02-10 17:23:27 +00:00
Vaxry
658f718fa3 input: partially revert #4514
issues with refocus in #4649
2024-02-10 17:05:38 +00:00
Sefa Eyeoglu
334a0f03ee keybinds: Fix focus not moving along when moving workspace (#4660)
---------

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2024-02-09 23:47:00 +00:00
Ben Landon
289d4241be groupbar: scale groupbar text according to monitor scale (#4640) 2024-02-08 22:29:10 +00:00
Vaxry
a6ccd36147 screencopy: move monitor verif check to the proper place
oops
2024-02-07 23:47:14 +00:00
thejch
3d9ca6381d crashreporter: fix logging of function data (#4632) 2024-02-07 09:50:23 +00:00
Vaxry
f085ed4454 screencopy/toplevelexport: sanitize pointers in ::copyFrame
oopsie~~ >///<
2024-02-07 00:18:47 +00:00
Vaxry
ded174d6e5 misc: remove unused var 2024-02-05 23:39:19 +00:00
Vaxry
181f651de2 vector: avoid min0 clamps without a max being invalid 2024-02-05 22:37:34 +00:00
Epilepsy Gatherings
8a6e428d32 keybinds: focusWorkspaceOnCurrentMonitor: use focused monitor instead (#4625) 2024-02-05 22:36:22 +00:00
Vaxry
1fd82e37a7 xwaylandmgr: proper clamping for setWindowSize
closes #4622 fixes #4621
2024-02-05 20:56:20 +00:00
Vaxry
f9202f791e xwaylandmgr: clamp size in setWindowSize
fixes #4586
2024-02-05 14:08:08 +00:00
140 changed files with 8818 additions and 6052 deletions

View File

@@ -13,7 +13,7 @@ body:
id: ver
attributes:
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>
<summary>System/Version info</summary>
@@ -63,5 +63,5 @@ body:
description: |
Anything that can help. Please always ATTACH and not paste them.
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

@@ -12,6 +12,7 @@ runs:
- name: Get required pacman pkgs
shell: bash
run: |
sed -i -e "1i [extra-testing]\nInclude = /etc/pacman.d/mirrorlist" "/etc/pacman.conf"
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
pacman --noconfirm --noprogressbar -Syyu
pacman --noconfirm --noprogressbar -Sy \
@@ -23,6 +24,7 @@ runs:
glm \
glslang \
go \
hyprlang \
jq \
libc++ \
libdisplay-info \
@@ -50,7 +52,18 @@ runs:
wayland-protocols \
xcb-util-errors \
xcb-util-renderutil \
xcb-util-wm
xcb-util-wm \
libzip \
librsvg
- name: Get hyprcursor-git
shell: bash
run: |
git clone https://github.com/hyprwm/hyprcursor --recursive
cd hyprcursor
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
cmake --install build
- name: Get Xorg pacman pkgs
shell: bash

View File

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

View File

@@ -19,7 +19,7 @@ jobs:
with:
ref: ${{ github.ref }}
- uses: DeterminateSystems/nix-installer-action@main
- uses: cachix/install-nix-action@v25
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v12
with:

View File

@@ -24,44 +24,3 @@ jobs:
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: ${{github.workspace}}/flawfinder_results.sarif
codeql:
name: CodeQL
runs-on: ubuntu-latest
container:
image: archlinux
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
steps:
- name: Checkout repository actions
uses: actions/checkout@v4
with:
sparse-checkout: .github/actions
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
- name: Setup base
uses: ./.github/actions/setup_base
with:
INSTALL_XORG_PKGS: true
- name: Build Hyprland
run: |
make all
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

2
.gitignore vendored
View File

@@ -31,3 +31,5 @@ gmon.out
PKGBUILD
src/version.h
.direnv

View File

@@ -101,7 +101,7 @@ message(STATUS "Checking deps...")
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1) # we do not check for wlroots, as we provide it ourselves
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
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")

View File

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

View File

@@ -75,6 +75,7 @@ pluginenv:
installheaders:
@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/protocols
mkdir -p ${PREFIX}/include/hyprland/wlroots
@@ -106,3 +107,24 @@ man:
--variable=section:1 \
--from rst \
--to man > ./docs/hyprctl.1
asan:
@echo -en "!!WARNING!!\nOnly run this in the TTY.\n"
@pidof Hyprland > /dev/null && echo -ne "Refusing to run with Hyprland running.\n" || echo ""
@pidof Hyprland > /dev/null && exit 1 || echo ""
rm -rf ./wayland
git reset --hard
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 ..
cp ./wayland/build/src/libwayland-server.a .
@echo "Wayland done"
patch -p1 < ./scripts/hyprlandStaticAsan.diff
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DWITH_ASAN:STRING=True -DUSE_TRACY:STRING=False -DUSE_TRACY_GPU:STRING=False -S . -B ./build -G Ninja
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
@echo "Hyprland done"
ASAN_OPTIONS="detect_odr_violation=0,log_path=asan.log" HYPRLAND_NO_CRASHREPORTER=1 ./build/Hyprland -c ~/.config/hypr/hyprland.conf

View File

@@ -124,13 +124,13 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
[Wayfire]: https://github.com/WayfireWM/wayfire
[TinyWl]: https://gitlab.freedesktop.org/wlroots/wlroots/-/blob/master/tinywl/tinywl.c
[Sway]: https://github.com/swaywm/sway
[DWL]: https://github.com/djpohly/dwl
[DWL]: https://codeberg.org/dwl/dwl
<!----------------------------------{ Images }--------------------------------->
[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
[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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 MiB

After

Width:  |  Height:  |  Size: 5.9 MiB

View File

@@ -47,7 +47,7 @@ basically, directories in /tmp/hypr are your sessions.
## Obtaining the Hyprland Crash Report (v0.22.0beta and up)
If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `~/.hyprland`
If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `$HOME/.cache/hyprland`.
Go to the crash report directory and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.

View File

@@ -117,7 +117,8 @@ misc {
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
device:epic-mouse-v1 {
device {
name = epic-mouse-v1
sensitivity = -0.5
}
@@ -126,7 +127,7 @@ device:epic-mouse-v1 {
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
# See https://wiki.hyprland.org/Configuring/Keywords/ for more

99
flake.lock generated
View File

@@ -1,5 +1,29 @@
{
"nodes": {
"hyprcursor": {
"inputs": {
"hyprlang": "hyprlang",
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1711466786,
"narHash": "sha256-sArxGyUBiCA1in+q6t0QqT+ZJiZ1PyBp7cNPKLmREM0=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "d3876f34779cc03ee51e4aafc0d00a4f187c7544",
"type": "github"
},
"original": {
"owner": "hyprwm",
"repo": "hyprcursor",
"type": "github"
}
},
"hyprland-protocols": {
"inputs": {
"nixpkgs": [
@@ -26,16 +50,40 @@
"hyprlang": {
"inputs": {
"nixpkgs": [
"xdph",
"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": {
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1704287638,
"narHash": "sha256-TuRXJGwtK440AXQNl5eiqmQqY4LZ/9+z/R7xC0ie3iA=",
"lastModified": 1711250455,
"narHash": "sha256-LSq1ZsTpeD7xsqvlsepDEelWRDtAhqwetp6PusHXJRo=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "6624f2bb66d4d27975766e81f77174adbe58ec97",
"rev": "b3e430f81f3364c5dd1a3cc9995706a4799eb3fa",
"type": "github"
},
"original": {
@@ -46,11 +94,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1706191920,
"narHash": "sha256-eLihrZAPZX0R6RyM5fYAWeKVNuQPYjAkCUBr+JNvtdE=",
"lastModified": 1711523803,
"narHash": "sha256-UKcYiHWHQynzj6CN/vTcix4yd1eCu1uFdsuarupdCQQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ae5c332cbb5827f6b1f02572496b141021de335f",
"rev": "2726f127c15a4cc9810843b96cad73c7eb39e443",
"type": "github"
},
"original": {
@@ -62,9 +110,11 @@
},
"root": {
"inputs": {
"hyprcursor": "hyprcursor",
"hyprland-protocols": "hyprland-protocols",
"hyprlang": "hyprlang_2",
"nixpkgs": "nixpkgs",
"systems": "systems",
"systems": "systems_2",
"wlroots": "wlroots",
"xdph": "xdph"
}
@@ -84,22 +134,37 @@
"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": {
"flake": false,
"locked": {
"host": "gitlab.freedesktop.org",
"lastModified": 1706359063,
"narHash": "sha256-5HUTG0p+nCJv3cn73AmFHRZdfRV5AD5N43g8xAePSKM=",
"lastModified": 1709983277,
"narHash": "sha256-wXWIJLd4F2JZeMaihWVDW/yYXCLEC8OpeNJZg9a9ly8=",
"owner": "wlroots",
"repo": "wlroots",
"rev": "00b869c1a96f300a8f25da95d624524895e0ddf2",
"rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b",
"type": "gitlab"
},
"original": {
"host": "gitlab.freedesktop.org",
"owner": "wlroots",
"repo": "wlroots",
"rev": "00b869c1a96f300a8f25da95d624524895e0ddf2",
"rev": "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b",
"type": "gitlab"
}
},
@@ -108,7 +173,9 @@
"hyprland-protocols": [
"hyprland-protocols"
],
"hyprlang": "hyprlang",
"hyprlang": [
"hyprlang"
],
"nixpkgs": [
"nixpkgs"
],
@@ -117,11 +184,11 @@
]
},
"locked": {
"lastModified": 1706145785,
"narHash": "sha256-j9MP4fv2U/vdRKAXXc2gyMTmYwVnHP6kHx1/y6jprrU=",
"lastModified": 1709299639,
"narHash": "sha256-jYqJM5khksLIbqSxCLUUcqEgI+O2LdlSlcMEBs39CAU=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "5a592647587cd20b9692a347df6939b6d371b3bb",
"rev": "2d2fb547178ec025da643db57d40a971507b82fe",
"type": "github"
},
"original": {

View File

@@ -12,21 +12,34 @@
host = "gitlab.freedesktop.org";
owner = "wlroots";
repo = "wlroots";
rev = "00b869c1a96f300a8f25da95d624524895e0ddf2";
rev = "50eae512d9cecbf0b3b1898bb1f0b40fa05fe19b";
flake = false;
};
hyprcursor = {
url = "github:hyprwm/hyprcursor";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
hyprland-protocols = {
url = "github:hyprwm/hyprland-protocols";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
hyprlang = {
url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
};
xdph = {
url = "github:hyprwm/xdg-desktop-portal-hyprland";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
inputs.hyprland-protocols.follows = "hyprland-protocols";
inputs.hyprlang.follows = "hyprlang";
};
};
@@ -64,9 +77,9 @@
# hyprland-packages
hyprland
hyprland-unwrapped
hyprland-debug
hyprland-legacy-renderer
hyprland-unwrapped
# hyprland-extras
xdg-desktop-portal-hyprland
@@ -84,9 +97,9 @@
stdenv = pkgsFor.${system}.gcc13Stdenv;
} {
name = "hyprland-shell";
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
nativeBuildInputs = with pkgsFor.${system}; [cmake python3 expat libxml2];
buildInputs = [self.packages.${system}.wlroots-hyprland];
hardeningDisable = [ "fortify" ];
hardeningDisable = ["fortify"];
inputsFrom = [
self.packages.${system}.wlroots-hyprland
self.packages.${system}.hyprland

View File

@@ -22,6 +22,7 @@
#include <deque>
#include <filesystem>
#include <stdarg.h>
#include <regex>
const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args]
@@ -30,9 +31,11 @@ commands:
activeworkspace
binds
clients
configerrors
cursorpos
decorations
devices
dismissnotify
dispatch
getoption
globalshortcuts
@@ -44,8 +47,10 @@ commands:
layouts
monitors
notify
output
plugin
reload
rollinglog
setcursor
seterror
setprop
@@ -58,6 +63,7 @@ commands:
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)
)#";
@@ -78,7 +84,7 @@ std::vector<SInstanceData> instances() {
std::vector<SInstanceData> result;
for (const auto& el : std::filesystem::directory_iterator("/tmp/hypr")) {
if (el.is_directory())
if (el.is_directory() || !el.path().string().ends_with(".lock"))
continue;
// read lock
@@ -86,7 +92,9 @@ std::vector<SInstanceData> instances() {
data->id = el.path().string();
data->id = data->id.substr(data->id.find_last_of('/') + 1, data->id.find(".lock") - data->id.find_last_of('/') - 1);
try {
data->time = std::stoull(data->id.substr(data->id.find_first_of('_') + 1));
} catch (std::exception& e) { continue; }
// read file
std::ifstream ifs(el.path().string());
@@ -94,7 +102,9 @@ std::vector<SInstanceData> instances() {
int i = 0;
for (std::string line; std::getline(ifs, line); ++i) {
if (i == 0) {
try {
data->pid = std::stoull(line);
} catch (std::exception& e) { continue; }
} else if (i == 1) {
data->wlSocket = line;
} else
@@ -225,9 +235,14 @@ void requestHyprpaper(std::string arg) {
std::cout << std::string(buffer);
}
void batchRequest(std::string arg) {
std::string rq = "[[BATCH]]" + arg.substr(arg.find_first_of(" ") + 1);
void batchRequest(std::string arg, bool json) {
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);
}
@@ -301,6 +316,10 @@ int main(int argc, char** argv) {
if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
fullArgs += "j";
json = true;
} else if (ARGS[i] == "-r" && !fullArgs.contains("r")) {
fullArgs += "r";
} else if (ARGS[i] == "-a" && !fullArgs.contains("a")) {
fullArgs += "a";
} else if (ARGS[i] == "--batch") {
fullRequest = "--batch ";
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
@@ -360,7 +379,7 @@ int main(int argc, char** argv) {
const auto ISIG = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!ISIG) {
std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)";
std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)\n";
return 1;
}
@@ -370,45 +389,9 @@ int main(int argc, char** argv) {
int exitStatus = 0;
if (fullRequest.contains("/--batch"))
batchRequest(fullRequest);
else if (fullRequest.contains("/monitors"))
request(fullRequest);
else if (fullRequest.contains("/clients"))
request(fullRequest);
else if (fullRequest.contains("/workspaces"))
request(fullRequest);
else if (fullRequest.contains("/activeworkspace"))
request(fullRequest);
else if (fullRequest.contains("/workspacerules"))
request(fullRequest);
else if (fullRequest.contains("/activewindow"))
request(fullRequest);
else if (fullRequest.contains("/layers"))
request(fullRequest);
else if (fullRequest.contains("/version"))
request(fullRequest);
else if (fullRequest.contains("/kill"))
request(fullRequest);
else if (fullRequest.contains("/systeminfo"))
request(fullRequest);
else if (fullRequest.contains("/splash"))
request(fullRequest);
else if (fullRequest.contains("/devices"))
request(fullRequest);
else if (fullRequest.contains("/reload"))
request(fullRequest);
else if (fullRequest.contains("/getoption"))
request(fullRequest);
else if (fullRequest.contains("/binds"))
request(fullRequest);
else if (fullRequest.contains("/cursorpos"))
request(fullRequest);
else if (fullRequest.contains("/animations"))
request(fullRequest);
else if (fullRequest.contains("/globalshortcuts"))
request(fullRequest);
else if (fullRequest.contains("/rollinglog"))
request(fullRequest);
batchRequest(fullRequest, json);
else if (fullRequest.contains("/hyprpaper"))
requestHyprpaper(fullRequest);
else if (fullRequest.contains("/switchxkblayout"))
request(fullRequest, 2);
else if (fullRequest.contains("/seterror"))
@@ -417,6 +400,8 @@ int main(int argc, char** argv) {
request(fullRequest, 3);
else if (fullRequest.contains("/plugin"))
request(fullRequest, 1);
else if (fullRequest.contains("/dismissnotify"))
request(fullRequest, 0);
else if (fullRequest.contains("/notify"))
request(fullRequest, 2);
else if (fullRequest.contains("/output"))
@@ -429,15 +414,10 @@ int main(int argc, char** argv) {
request(fullRequest, 2);
else if (fullRequest.contains("/decorations"))
request(fullRequest, 1);
else if (fullRequest.contains("/hyprpaper"))
requestHyprpaper(fullRequest);
else if (fullRequest.contains("/layouts"))
request(fullRequest);
else if (fullRequest.contains("/--help"))
printf("%s", USAGE.c_str());
else {
printf("%s\n", USAGE.c_str());
return 1;
request(fullRequest);
}
printf("\n");

View File

@@ -45,11 +45,13 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
{"repository", toml::table{
{"name", repo.name},
{"hash", repo.hash},
{"url", repo.url}
{"url", repo.url},
{"rev", repo.rev}
}}
};
for (auto& p : repo.plugins) {
// copy .so to the good place
if (std::filesystem::exists(p.filename))
std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so");
DATA.emplace(p.name, toml::table{
@@ -177,12 +179,14 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
const auto NAME = STATE["repository"]["name"].value_or("");
const auto URL = STATE["repository"]["url"].value_or("");
const auto REV = STATE["repository"]["rev"].value_or("");
const auto HASH = STATE["repository"]["hash"].value_or("");
SPluginRepository repo;
repo.hash = HASH;
repo.name = NAME;
repo.url = URL;
repo.rev = REV;
for (const auto& [key, val] : STATE) {
if (key == "repository")

View File

@@ -12,6 +12,7 @@ struct SPlugin {
struct SPluginRepository {
std::string url;
std::string rev;
std::string name;
std::vector<SPlugin> plugins;
std::string hash;

View File

@@ -77,8 +77,7 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
return ver;
}
bool CPluginManager::addNewPluginRepo(const std::string& url) {
bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& rev) {
const auto HLVER = getHyprlandVersion();
if (DataState::pluginRepoExists(url)) {
@@ -134,6 +133,14 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
return false;
}
if (!rev.empty()) {
std::string ret = execAndGet("git -C /tmp/hyprpm/new reset --hard --recurse-submodules " + rev);
if (ret.compare(0, 6, "fatal:") == 0) {
std::cerr << "\n" << Colors::RED << "" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n";
return false;
}
}
progress.m_iSteps = 1;
progress.printMessageAbove(std::string{Colors::GREEN} + "" + Colors::RESET + " cloned");
progress.m_szCurrentMessage = "Reading the manifest";
@@ -214,12 +221,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
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)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\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");
p.failed = true;
continue;
@@ -240,6 +247,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
repohash.pop_back();
repo.name = pManifest->m_sRepository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_sRepository.name;
repo.url = url;
repo.rev = rev;
repo.hash = repohash;
for (auto& p : pManifest->m_vPlugins) {
repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false, p.failed});
@@ -325,7 +333,12 @@ eHeadersErrors CPluginManager::headersValid() {
std::string verHeaderContent((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
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(hash.find_first_of('"') + 1);
hash = hash.substr(0, hash.find_first_of('"'));
@@ -494,6 +507,16 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
return false;
}
if (!repo.rev.empty()) {
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);
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;
return false;
}
}
if (!update) {
// check if git has updates
std::string hash = execAndGet("cd /tmp/hyprpm/update && git rev-parse HEAD");
@@ -538,8 +561,8 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
continue;
}
if (!pManifest->m_sRepository.commitPins.empty()) {
// check commit pins
if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) {
// check commit pins unless a revision is specified
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
@@ -564,11 +587,12 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
}
if (m_bVerbose)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\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)
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
break;
}

View File

@@ -36,7 +36,7 @@ struct SHyprlandVersion {
class CPluginManager {
public:
bool addNewPluginRepo(const std::string& url);
bool addNewPluginRepo(const std::string& url, const std::string& rev);
bool removePluginRepo(const std::string& urlOrName);
eHeadersErrors headersValid();

View File

@@ -11,7 +11,8 @@
const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
add [url] Install a new plugin repository from git
add [url] [git rev] Install a new plugin repository from git. Git revision
is optional, when set, commit locks are ignored.
remove [url/name] Remove an installed plugin repository
enable [name] Enable a plugin
disable [name] Disable a plugin
@@ -55,7 +56,7 @@ int main(int argc, char** argv, char** envp) {
force = true;
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
} else {
std::cerr << "Unrecognized option " << ARGS[i];
std::cerr << "Unrecognized option " << ARGS[i] << "\n";
return 1;
}
} else {
@@ -77,7 +78,12 @@ int main(int argc, char** argv, char** envp) {
return 1;
}
return g_pPluginManager->addNewPluginRepo(command[1]) ? 0 : 1;
std::string rev = "";
if (command.size() >= 3) {
rev = command[2];
}
return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1;
} else if (command[0] == "remove") {
if (ARGS.size() < 2) {
std::cerr << Colors::RED << "" << Colors::RESET << " Not enough args for remove.\n";

View File

@@ -8,10 +8,13 @@
binutils,
cairo,
git,
hyprcursor,
hyprland-protocols,
hyprlang,
jq,
libGL,
libdrm,
libexecinfo,
libinput,
libxcb,
libxkbcommon,
@@ -42,7 +45,9 @@
}:
assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed.";
assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed.";
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland";
assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; let
wlr = wlroots.override {inherit enableXWayland;};
in
stdenv.mkDerivation {
pname = "hyprland${lib.optionalString debug "-debug"}";
inherit version;
@@ -55,55 +60,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
src = lib.cleanSource ../.;
};
nativeBuildInputs = [
jq
meson
ninja
pkg-config
makeWrapper
wayland-scanner
];
outputs = [
"out"
"man"
"dev"
];
buildInputs =
[
cairo
git
hyprland-protocols
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 = [
# make meson use the provided wlroots instead of the git submodule
./patches/meson-build.patch
@@ -128,8 +84,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 =
[
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 = ''
ln -s ${wlroots}/include/wlr $dev/include/hyprland/wlroots
ln -s ${wlr}/include/wlr $dev/include/hyprland/wlroots
${lib.optionalString wrapRuntimeDeps ''
wrapProgram $out/bin/Hyprland \
--suffix PATH : ${lib.makeBinPath [
@@ -143,10 +152,10 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
passthru.providedSessions = ["hyprland"];
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";
license = licenses.bsd3;
platforms = platforms.linux;
platforms = wlr.meta.platforms;
mainProgram = "Hyprland";
};
}

View File

@@ -21,7 +21,9 @@ in {
# Packages for variations of Hyprland, dependencies included.
hyprland-packages = lib.composeManyExtensions [
# Dependencies
inputs.hyprcursor.overlays.default
inputs.hyprland-protocols.overlays.default
inputs.hyprlang.overlays.default
self.overlays.wlroots-hyprland
self.overlays.udis86
# Hyprland packages themselves
@@ -31,9 +33,9 @@ in {
hyprland = final.callPackage ./default.nix {
stdenv = final.gcc13Stdenv;
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
wlroots = prev.wlroots-hyprland;
commit = self.rev or "";
inherit (final) udis86 hyprland-protocols;
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
inherit date;
};
hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
@@ -61,7 +63,7 @@ in {
];
udis86 = final: prev: {
udis86 = final.callPackage ./udis86.nix {};
udis86-hyprland = final.callPackage ./udis86.nix {};
};
# Patched version of wlroots for Hyprland.

View File

@@ -34,17 +34,19 @@ index 1d2c7f9f..c5ef4e67 100644
headers = globber.stdout().strip().split('\n')
foreach file : headers
diff --git a/src/meson.build b/src/meson.build
index 0af864b9..38723b8c 100644
index 45701f5f..3505cefe 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -9,16 +9,16 @@ executable('Hyprland', src,
@@ -9,7 +9,7 @@ executable('Hyprland', src,
server_protos,
dependency('wayland-server'),
dependency('wayland-client'),
- wlroots.get_variable('wlroots'),
+ dependency('wlroots'),
dependency('cairo'),
dependency('libdrm'),
dependency('hyprcursor'),
dependency('hyprlang', version: '>= 0.3.2'),
@@ -16,12 +16,12 @@ executable('Hyprland', src,
dependency('egl'),
dependency('xkbcommon'),
dependency('libinput'),

View File

@@ -1,3 +1,3 @@
{
"version": "0.35.0"
"version": "0.38.0"
}

View File

@@ -0,0 +1,21 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 71766a8c..bd8cdc0e 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -101,7 +101,7 @@ message(STATUS "Checking deps...")
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED)
-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
+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 libffi) # we do not check for wlroots, as we provide it ourselves
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
@@ -121,6 +121,7 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Enabling ASan")
target_link_libraries(Hyprland asan)
+ target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/libwayland-server.a)
target_compile_options(Hyprland PUBLIC -fsanitize=address)
endif()

View File

@@ -0,0 +1,23 @@
diff --git a/src/meson.build b/src/meson.build
index 5d04334..6645eec 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -170,7 +170,7 @@ if get_option('libraries')
error('We probably need to bump the SONAME of libwayland-server and -client')
endif
- wayland_server = library(
+ wayland_server = static_library(
'wayland-server',
sources: [
wayland_server_protocol_core_h,
@@ -180,9 +180,6 @@ if get_option('libraries')
'wayland-shm.c',
'event-loop.c'
],
- # To avoid an unnecessary SONAME bump, wayland 1.x.y produces
- # libwayland-server.so.0.x.y.
- version: '.'.join(['0', wayland_version[1], wayland_version[2]]),
dependencies: [
epoll_dep,
ffi_dep,

View File

@@ -1,5 +1,7 @@
#include "Compositor.hpp"
#include "helpers/Splashes.hpp"
#include "config/ConfigValue.hpp"
#include "managers/CursorManager.hpp"
#include <random>
#include <unordered_set>
#include "debug/HyprCtl.hpp"
@@ -8,6 +10,7 @@
#include <systemd/sd-daemon.h> // for sd_notify
#endif
#include <ranges>
#include "helpers/VarList.hpp"
int handleCritSignal(int signo, void* data) {
Debug::log(LOG, "Hyprland received signal {}", signo);
@@ -99,8 +102,11 @@ void CCompositor::initServer() {
// register crit signal handler
wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr);
if (!envEnabled("HYPRLAND_NO_CRASHREPORTER")) {
signal(SIGSEGV, handleUnrecoverableSignal);
signal(SIGABRT, handleUnrecoverableSignal);
}
signal(SIGUSR1, handleUserSignal);
initManagers(STAGE_PRIORITY);
@@ -122,6 +128,18 @@ void CCompositor::initServer() {
throwError("wlr_backend_autocreate() failed!");
}
bool isHeadlessOnly = true;
wlr_multi_for_each_backend(
m_sWLRBackend,
[](wlr_backend* backend, void* isHeadlessOnly) {
if (!wlr_backend_is_headless(backend))
*(bool*)isHeadlessOnly = false;
},
&isHeadlessOnly);
if (isHeadlessOnly) {
m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend);
} else {
m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend);
if (m_iDRMFD < 0) {
Debug::log(CRIT, "Couldn't query the DRM FD!");
@@ -129,6 +147,7 @@ void CCompositor::initServer() {
}
m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD);
}
if (!m_sWLRRenderer) {
Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
@@ -178,18 +197,6 @@ void CCompositor::initServer() {
m_sWLRCursor = wlr_cursor_create();
wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout);
if (const auto XCURSORENV = getenv("XCURSOR_SIZE"); !XCURSORENV || std::string(XCURSORENV).empty())
setenv("XCURSOR_SIZE", "24", true);
const auto XCURSORENV = getenv("XCURSOR_SIZE");
int cursorSize = 24;
try {
cursorSize = std::stoi(XCURSORENV);
} catch (std::exception& e) { Debug::log(ERR, "XCURSOR_SIZE invalid in check #2? ({})", XCURSORENV); }
m_sWLRXCursorMgr = wlr_xcursor_manager_create(nullptr, cursorSize);
wlr_xcursor_manager_load(m_sWLRXCursorMgr, 1);
m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0");
m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend);
@@ -304,6 +311,7 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRGammaCtrlMgr->events.set_gamma, &Events::listen_setGamma, m_sWLRGammaCtrlMgr, "GammaCtrlMgr");
addWLSignal(&m_sWLRCursorShapeMgr->events.request_set_shape, &Events::listen_setCursorShape, m_sWLRCursorShapeMgr, "CursorShapeMgr");
addWLSignal(&m_sWLRTearingControlMgr->events.new_object, &Events::listen_newTearingHint, m_sWLRTearingControlMgr, "TearingControlMgr");
addWLSignal(&m_sWLRKbShInhibitMgr->events.new_inhibitor, &Events::listen_newShortcutInhibitor, m_sWLRKbShInhibitMgr, "ShortcutInhibitMgr");
if (m_sWRLDRMLeaseMgr)
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
@@ -357,6 +365,7 @@ void CCompositor::removeAllSignals() {
removeWLSignal(&Events::listen_setGamma);
removeWLSignal(&Events::listen_setCursorShape);
removeWLSignal(&Events::listen_newTearingHint);
removeWLSignal(&Events::listen_newShortcutInhibitor);
if (m_sWRLDRMLeaseMgr)
removeWLSignal(&Events::listen_leaseRequest);
@@ -369,6 +378,9 @@ void CCompositor::cleanup() {
if (!m_sWLDisplay || m_bIsShuttingDown)
return;
signal(SIGABRT, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
removeLockFile();
m_bIsShuttingDown = true;
@@ -408,9 +420,12 @@ void CCompositor::cleanup() {
removeAllSignals();
g_pInputManager.reset();
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
g_pDecorationPositioner.reset();
g_pCursorManager.reset();
g_pPluginSystem.reset();
g_pHyprNotificationOverlay.reset();
g_pDebugOverlay.reset();
@@ -419,7 +434,6 @@ void CCompositor::cleanup() {
g_pProtocolManager.reset();
g_pHyprRenderer.reset();
g_pHyprOpenGL.reset();
g_pInputManager.reset();
g_pThreadManager.reset();
g_pConfigManager.reset();
g_pLayoutManager.reset();
@@ -501,6 +515,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the DecorationPositioner!");
g_pDecorationPositioner = std::make_unique<CDecorationPositioner>();
Debug::log(LOG, "Creating the CursorManager!");
g_pCursorManager = std::make_unique<CCursorManager>();
} break;
default: UNREACHABLE();
}
@@ -677,6 +694,8 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) {
if (windowExists(pWindow) && !pWindow->m_bFadingOut)
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) {
@@ -688,12 +707,21 @@ bool CCompositor::windowExists(CWindow* pWindow) {
return false;
}
bool CCompositor::monitorExists(CMonitor* pMonitor) {
for (auto& m : m_vRealMonitors) {
if (m.get() == pMonitor)
return true;
}
return false;
}
CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, CWindow* pIgnoreWindow) {
const auto PMONITOR = getMonitorFromVector(pos);
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
static auto* const PSPECIALFALLTHRU = &g_pConfigManager->getConfigValuePtr("input:special_fallthrough")->intValue;
static auto PRESIZEONBORDER = CConfigValue<Hyprlang::INT>("general:resize_on_border");
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
static auto PBORDERGRABEXTEND = CConfigValue<Hyprlang::INT>("general:extend_border_grab_area");
static auto PSPECIALFALLTHRU = CConfigValue<Hyprlang::INT>("input:special_fallthrough");
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
// pinned windows on top of floating regardless
@@ -701,7 +729,8 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowBoxUnified(properties);
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 && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus &&
w.get() != pIgnoreWindow) {
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
return w.get();
@@ -714,16 +743,24 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
}
auto windowForWorkspace = [&](bool special) -> CWindow* {
if (properties & ALLOW_FLOATING) {
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
auto floating = [&](bool aboveFullscreen) -> CWindow* {
for (auto& w : m_vWindows | std::views::reverse) {
if (special && !isWorkspaceSpecial(w->m_iWorkspaceID)) // because special floating may creep up into regular
continue;
const auto BB = w->getWindowBoxUnified(properties);
const auto PWINDOWMONITOR = getMonitorFromID(w->m_iMonitorID);
// to avoid focusing windows behind special workspaces from other monitors
if (!*PSPECIALFALLTHRU && PWINDOWMONITOR && PWINDOWMONITOR->specialWorkspaceID && w->m_iWorkspaceID != PWINDOWMONITOR->specialWorkspaceID &&
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)
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};
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus &&
w.get() != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) {
// OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
continue;
@@ -745,10 +782,19 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
}
}
}
return nullptr;
};
if (properties & ALLOW_FLOATING) {
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
auto found = floating(true);
if (found)
return found;
}
if (properties & FLOATING_ONLY)
return nullptr;
return floating(false);
const int64_t WORKSPACEID = special ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID);
@@ -756,13 +802,17 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
if (PWORKSPACE->m_bHasFullscreenWindow)
return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
auto found = floating(false);
if (found)
return found;
// for windows, we need to check their extensions too, first.
for (auto& w : m_vWindows) {
if (special != isWorkspaceSpecial(w->m_iWorkspaceID))
continue;
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus &&
w.get() != pIgnoreWindow) {
if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w.get() != pIgnoreWindow) {
if (w->hasPopupAt(pos))
return w.get();
}
@@ -773,8 +823,8 @@ CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t propert
continue;
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 && !w->m_bNoFocus &&
w.get() != pIgnoreWindow)
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus &&
!w->m_sAdditionalConfigData.noFocus && w.get() != pIgnoreWindow)
return w.get();
}
@@ -811,7 +861,8 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, geom.pWlr());
geom.applyFromWlr();
const auto PFOUND = wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.vec().x + geom.x, pos.y - pWindow->m_vRealPosition.vec().y + geom.y, &subx, &suby);
const auto PFOUND =
wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.value().x + geom.x, pos.y - pWindow->m_vRealPosition.value().y + geom.y, &subx, &suby);
if (PFOUND) {
sl.x = subx;
@@ -819,8 +870,8 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
return PFOUND;
}
sl.x = pos.x - pWindow->m_vRealPosition.vec().x;
sl.y = pos.y - pWindow->m_vRealPosition.vec().y;
sl.x = pos.x - pWindow->m_vRealPosition.value().x;
sl.y = pos.y - pWindow->m_vRealPosition.value().y;
sl.x += geom.x;
sl.y += geom.y;
@@ -833,7 +884,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, CWindow* pWindow
return {};
if (pWindow->m_bIsX11)
return vec - pWindow->m_vRealPosition.goalv();
return vec - pWindow->m_vRealPosition.goal();
const auto PSURFACE = pWindow->m_uSurface.xdg;
@@ -855,9 +906,9 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, CWindow* pWindow
geom.applyFromWlr();
if (std::get<1>(iterData) == -1337 && std::get<2>(iterData) == -1337)
return vec - pWindow->m_vRealPosition.goalv();
return vec - pWindow->m_vRealPosition.goal();
return vec - pWindow->m_vRealPosition.goalv() - Vector2D{std::get<1>(iterData), std::get<2>(iterData)} + Vector2D{geom.x, geom.y};
return vec - pWindow->m_vRealPosition.goal() - Vector2D{std::get<1>(iterData), std::get<2>(iterData)} + Vector2D{geom.x, geom.y};
}
CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
@@ -870,10 +921,20 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
return nullptr;
}
CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) {
for (auto& m : m_vRealMonitors) {
if (m->output == out) {
return m.get();
}
}
return nullptr;
}
void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
static auto* const PSPECIALFALLTHROUGH = &g_pConfigManager->getConfigValuePtr("input:special_fallthrough")->intValue;
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
static auto PSPECIALFALLTHROUGH = CConfigValue<Hyprlang::INT>("input:special_fallthrough");
if (g_pCompositor->m_sSeat.exclusiveClient) {
Debug::log(LOG, "Disallowing setting focus to a window due to there being an active input inhibitor layer.");
@@ -885,6 +946,9 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
return;
}
if (pWindow && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(pWindow->m_uSurface.xwayland))
return;
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
if (!pWindow || !windowValidMapped(pWindow)) {
@@ -919,7 +983,7 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
return;
}
if (pWindow->m_bNoFocus) {
if (pWindow->m_sAdditionalConfigData.noFocus) {
Debug::log(LOG, "Ignoring focus to nofocus window!");
return;
}
@@ -997,13 +1061,6 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
if (pWindow->m_phForeignToplevel)
wlr_foreign_toplevel_handle_v1_set_activated(pWindow->m_phForeignToplevel, true);
if (!pWindow->m_bIsX11) {
const auto PCONSTRAINT = wlr_pointer_constraints_v1_constraint_for_surface(m_sWLRPointerConstraints, pWindow->m_uSurface.xdg->surface, m_sSeat.seat);
if (PCONSTRAINT)
g_pInputManager->constrainMouse(m_sSeat.mouse, PCONSTRAINT);
}
g_pInputManager->recheckIdleInhibitorStatus();
// move to front of the window history
@@ -1026,6 +1083,8 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface))
return;
const auto PLASTSURF = m_pLastFocus;
// Unfocus last surface if should
if (m_pLastFocus && !pWindowOwner)
g_pXWaylandManager->activateSurface(m_pLastFocus, false);
@@ -1060,6 +1119,15 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
m_pLastFocus = pSurface;
EMIT_HOOK_EVENT("keyboardFocus", pSurface);
const auto SURF = CWLSurface::surfaceFromWlr(pSurface);
const auto OLDSURF = CWLSurface::surfaceFromWlr(PLASTSURF);
if (OLDSURF && OLDSURF->constraint())
OLDSURF->constraint()->deactivate();
if (SURF && SURF->constraint())
SURF->constraint()->activate();
}
bool CCompositor::windowValidMapped(CWindow* pWindow) {
@@ -1078,10 +1146,22 @@ bool CCompositor::windowValidMapped(CWindow* pWindow) {
return true;
}
CWindow* CCompositor::getWindowForPopup(wlr_xdg_popup* popup) {
for (auto& p : m_vXDGPopups) {
if (p->popup == popup)
return p->parentWindow;
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;
@@ -1090,10 +1170,10 @@ CWindow* CCompositor::getWindowForPopup(wlr_xdg_popup* popup) {
wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<std::unique_ptr<SLayerSurface>>* layerSurfaces, Vector2D* sCoords,
SLayerSurface** ppLayerSurfaceFound) {
for (auto& ls : *layerSurfaces | std::views::reverse) {
if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.fl() == 0.f)
if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f)
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 (!pixman_region32_not_empty(&SURFACEAT->input_region))
@@ -1107,21 +1187,6 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
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) {
for (auto& w : m_vWindows) {
if (!w->m_bIsMapped || w->m_bFadingOut)
@@ -1195,8 +1260,13 @@ void CCompositor::sanityCheckWorkspaces() {
auto it = m_vWorkspaces.begin();
while (it != m_vWorkspaces.end()) {
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(it->get());
if (WORKSPACERULE.isPersistent) {
const auto WORKSPACERULES = g_pConfigManager->getWorkspaceRulesFor(it->get());
bool isPersistent = false;
for (auto& wsRule : WORKSPACERULES) {
if (wsRule.isPersistent)
isPersistent = true;
}
if (isPersistent) {
++it;
continue;
}
@@ -1208,7 +1278,7 @@ void CCompositor::sanityCheckWorkspaces() {
if (!isWorkspaceVisible(WORKSPACE->m_iID)) {
if (WORKSPACE->m_bIsSpecialWorkspace) {
if (WORKSPACE->m_fAlpha.fl() > 0.f /* don't abruptly end the fadeout */) {
if (WORKSPACE->m_fAlpha.value() > 0.f /* don't abruptly end the fadeout */) {
++it;
continue;
}
@@ -1223,8 +1293,10 @@ void CCompositor::sanityCheckWorkspaces() {
continue;
}
if (!WORKSPACE->m_bOnCreatedEmptyExecuted) {
if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd)
for (auto& wsRule : WORKSPACERULES) {
if (auto cmd = wsRule.onCreatedEmptyRunCmd)
g_pKeybindManager->spawn(*cmd);
}
WORKSPACE->m_bOnCreatedEmptyExecuted = true;
}
@@ -1234,10 +1306,10 @@ void CCompositor::sanityCheckWorkspaces() {
}
}
int CCompositor::getWindowsOnWorkspace(const int& id) {
int CCompositor::getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled) {
int no = 0;
for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == id && w->m_bIsMapped)
if (w->m_iWorkspaceID == id && w->m_bIsMapped && !(onlyTiled.has_value() && !w->m_bIsFloating != onlyTiled.value()))
no++;
}
@@ -1389,12 +1461,16 @@ void CCompositor::cleanupFadingOut(const int& monid) {
bool valid = windowExists(w);
if (!valid || !w->m_bFadingOut || w->m_fAlpha.fl() == 0.f) {
if (valid && !w->m_bReadyToDelete)
if (!valid || !w->m_bFadingOut || w->m_fAlpha.value() == 0.f) {
if (valid) {
w->m_bFadingOut = false;
if (!w->m_bReadyToDelete)
continue;
w->m_bFadingOut = false;
removeWindowFromVectorSafe(w);
}
std::erase(m_vWindowsFadingOut, w);
Debug::log(LOG, "Cleanup: destroyed a window");
@@ -1438,7 +1514,7 @@ void CCompositor::cleanupFadingOut(const int& monid) {
if (ls->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || ls->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
g_pHyprOpenGL->markBlurDirtyForMonitor(getMonitorFromID(monid));
if (ls->fadingOut && ls->readyToDelete && !ls->alpha.isBeingAnimated()) {
if (ls->fadingOut && ls->readyToDelete && ls->isFadedOut()) {
for (auto& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLayers) {
if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](std::unique_ptr<SLayerSurface>& other) { return other.get() == ls; }) != lsl.end()) {
@@ -1481,7 +1557,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
return nullptr;
// 0 -> history, 1 -> shared length
static auto* const PMETHOD = &g_pConfigManager->getConfigValuePtr("binds:focus_preferred_method")->intValue;
static auto PMETHOD = CConfigValue<Hyprlang::INT>("binds:focus_preferred_method");
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -1502,7 +1578,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
// for tiled windows, we calc edges
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_iWorkspaceID))
continue;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID)
@@ -1591,7 +1667,7 @@ CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
constexpr float THRESHOLD = 0.3 * M_PI;
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_iWorkspaceID))
continue;
if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_iWorkspaceID != w->m_iWorkspaceID)
@@ -1637,7 +1713,7 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get();
}
@@ -1645,7 +1721,7 @@ CWindow* CCompositor::getNextWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get();
}
@@ -1666,7 +1742,7 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
if (w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get();
}
@@ -1674,7 +1750,7 @@ CWindow* CCompositor::getPrevWindowOnWorkspace(CWindow* pWindow, bool focusableO
if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_bNoFocus))
if (w.get() != pWindow && w->m_iWorkspaceID == pWindow->m_iWorkspaceID && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus))
return w.get();
}
@@ -1736,34 +1812,16 @@ void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) {
pair->second = pair->second || pSurface == pair->first;
}
CWindow* CCompositor::getConstraintWindow(SMouse* pMouse) {
if (!pMouse->currentConstraint)
return nullptr;
const auto PSURFACE = pMouse->currentConstraint->surface;
for (auto& w : m_vWindows) {
if (w->isHidden() || !w->m_bIsMapped || !w->m_pWLSurface.exists())
continue;
if (w->m_bIsX11) {
if (PSURFACE == w->m_pWLSurface.wlr())
return w.get();
} else {
std::pair<wlr_surface*, bool> check = {PSURFACE, false};
wlr_surface_for_each_surface(w->m_uSurface.xdg->surface, checkFocusSurfaceIter, &check);
if (check.second)
return w.get();
}
}
return nullptr;
CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
return this->getMonitorInDirection(m_pLastMonitor, dir);
}
CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
const auto POSA = m_pLastMonitor->vecPosition;
const auto SIZEA = m_pLastMonitor->vecSize;
CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const char& dir) {
if (!pSourceMonitor)
return nullptr;
const auto POSA = pSourceMonitor->vecPosition;
const auto SIZEA = pSourceMonitor->vecSize;
auto longestIntersect = -1;
CMonitor* longestIntersectMonitor = nullptr;
@@ -1842,21 +1900,30 @@ void CCompositor::updateWorkspaceWindows(const int64_t& id) {
void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
// optimization
static auto* const ACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.active_border")->data.get();
static auto* const INACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.inactive_border")->data.get();
static auto* const NOGROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border_active")->data.get();
static auto* const NOGROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("general:col.nogroup_border")->data.get();
static auto* const GROUPACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_active")->data.get();
static auto* const GROUPINACTIVECOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_inactive")->data.get();
static auto* const GROUPACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_active")->data.get();
static auto* const GROUPINACTIVELOCKEDCOL = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:col.border_locked_inactive")->data.get();
static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
static auto* const PFULLSCREENALPHA = &g_pConfigManager->getConfigValuePtr("decoration:fullscreen_opacity")->floatValue;
static auto* const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue;
static auto* const PSHADOWCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow_inactive")->intValue;
static auto* const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
static auto* const PDIMENABLED = &g_pConfigManager->getConfigValuePtr("decoration:dim_inactive")->intValue;
static auto PACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.active_border");
static auto PINACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.inactive_border");
static auto PNOGROUPACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.nogroup_border_active");
static auto PNOGROUPINACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("general:col.nogroup_border");
static auto PGROUPACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_active");
static auto PGROUPINACTIVECOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_inactive");
static auto PGROUPACTIVELOCKEDCOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_locked_active");
static auto PGROUPINACTIVELOCKEDCOL = CConfigValue<Hyprlang::CUSTOMTYPE>("group:col.border_locked_inactive");
static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity");
static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity");
static auto PFULLSCREENALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:fullscreen_opacity");
static auto PSHADOWCOL = CConfigValue<Hyprlang::INT>("decoration:col.shadow");
static auto PSHADOWCOLINACTIVE = CConfigValue<Hyprlang::INT>("decoration:col.shadow_inactive");
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
static auto PDIMENABLED = CConfigValue<Hyprlang::INT>("decoration:dim_inactive");
auto* const ACTIVECOL = (CGradientValueData*)(PACTIVECOL.ptr())->getData();
auto* const INACTIVECOL = (CGradientValueData*)(PINACTIVECOL.ptr())->getData();
auto* const NOGROUPACTIVECOL = (CGradientValueData*)(PNOGROUPACTIVECOL.ptr())->getData();
auto* const NOGROUPINACTIVECOL = (CGradientValueData*)(PNOGROUPINACTIVECOL.ptr())->getData();
auto* const GROUPACTIVECOL = (CGradientValueData*)(PGROUPACTIVECOL.ptr())->getData();
auto* const GROUPINACTIVECOL = (CGradientValueData*)(PGROUPINACTIVECOL.ptr())->getData();
auto* const GROUPACTIVELOCKEDCOL = (CGradientValueData*)(PGROUPACTIVELOCKEDCOL.ptr())->getData();
auto* const GROUPINACTIVELOCKEDCOL = (CGradientValueData*)(PGROUPINACTIVELOCKEDCOL.ptr())->getData();
auto setBorderColor = [&](CGradientValueData grad) -> void {
if (grad == pWindow->m_cRealBorderColor)
@@ -1965,7 +2032,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
// additionally, move floating and fs windows manually
if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.vec() - pMonitorA->vecPosition + pMonitorB->vecPosition;
w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorA->vecPosition + pMonitorB->vecPosition;
if (w->m_bIsFullscreen) {
w->m_vRealPosition = pMonitorB->vecPosition;
@@ -1990,7 +2057,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
// additionally, move floating and fs windows manually
if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.vec() - pMonitorB->vecPosition + pMonitorA->vecPosition;
w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorB->vecPosition + pMonitorA->vecPosition;
if (w->m_bIsFullscreen) {
w->m_vRealPosition = pMonitorA->vecPosition;
@@ -2004,23 +2071,41 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
pMonitorA->activeWorkspace = PWORKSPACEB->m_iID;
pMonitorB->activeWorkspace = PWORKSPACEA->m_iID;
PWORKSPACEA->rememberPrevWorkspace(PWORKSPACEB);
PWORKSPACEB->rememberPrevWorkspace(PWORKSPACEA);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitorA->ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitorB->ID);
updateFullscreenFadeOnWorkspace(PWORKSPACEB);
updateFullscreenFadeOnWorkspace(PWORKSPACEA);
g_pInputManager->sendMotionEventsToFocused();
if (pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID || pMonitorB->ID == g_pCompositor->m_pLastMonitor->ID) {
const auto LASTWIN = pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID ? PWORKSPACEB->getLastFocusedWindow() : PWORKSPACEA->getLastFocusedWindow();
g_pCompositor->focusWindow(LASTWIN ? LASTWIN :
(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
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)});
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<void*>{PWORKSPACEA, pMonitorB}));
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)});
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<void*>{PWORKSPACEB, pMonitorA}));
}
CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
if (name[0] == '+' || name[0] == '-') {
if (name == "current")
return g_pCompositor->m_pLastMonitor;
else if (isDirection(name))
return getMonitorInDirection(name[0]);
else if (name[0] == '+' || name[0] == '-') {
// relative
if (m_vMonitors.size() == 1)
@@ -2075,33 +2160,15 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1");
return nullptr;
}
} else if (name.starts_with("desc:")) {
const auto DESCRIPTION = name.substr(5);
} else {
for (auto& m : m_vMonitors) {
if (!m->output)
continue;
if (m->szDescription.starts_with(DESCRIPTION)) {
if (m->matchesStaticSelector(name)) {
return m.get();
}
}
return nullptr;
} else {
if (name == "current")
return g_pCompositor->m_pLastMonitor;
if (isDirection(name)) {
const auto PMONITOR = getMonitorInDirection(name[0]);
return PMONITOR;
} else {
for (auto& m : m_vMonitors) {
if (m->szName == name) {
return m.get();
}
}
}
}
return nullptr;
@@ -2147,7 +2214,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
}
Debug::log(LOG, "moveWorkspaceToMonitor: Plugging gap with existing {}", nextWorkspaceOnMonitorID);
POLDMON->changeWorkspace(nextWorkspaceOnMonitorID);
POLDMON->changeWorkspace(nextWorkspaceOnMonitorID, false, true, true);
}
// move the workspace
@@ -2167,14 +2234,14 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
if (w->m_bIsMapped && !w->isHidden()) {
if (POLDMON) {
if (w->m_bIsFloating)
w->m_vRealPosition = w->m_vRealPosition.vec() - POLDMON->vecPosition + pMonitor->vecPosition;
w->m_vRealPosition = w->m_vRealPosition.goal() - POLDMON->vecPosition + pMonitor->vecPosition;
if (w->m_bIsFullscreen) {
w->m_vRealPosition = pMonitor->vecPosition;
w->m_vRealSize = pMonitor->vecSize;
}
} else {
w->m_vRealPosition = Vector2D{(int)w->m_vRealPosition.goalv().x % (int)pMonitor->vecSize.x, (int)w->m_vRealPosition.goalv().y % (int)pMonitor->vecSize.y};
w->m_vRealPosition = Vector2D{(int)w->m_vRealPosition.goal().x % (int)pMonitor->vecSize.x, (int)w->m_vRealPosition.goal().y % (int)pMonitor->vecSize.y};
}
}
@@ -2188,6 +2255,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
if (const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace); PWORKSPACE)
getWorkspaceByID(pMonitor->activeWorkspace)->startAnim(false, false);
setActiveMonitor(pMonitor);
pMonitor->activeWorkspace = pWorkspace->m_iID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
@@ -2209,6 +2277,7 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
// event
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)});
EMIT_HOOK_EVENT("moveWorkspace", (std::vector<void*>{pWorkspace, pMonitor}));
}
@@ -2249,7 +2318,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(CWorkspace* pWorkspace) {
const auto PMONITOR = getMonitorFromID(pWorkspace->m_iMonitorID);
if (pWorkspace->m_iID == PMONITOR->activeWorkspace) {
if (pWorkspace->m_iID == PMONITOR->activeWorkspace || pWorkspace->m_iID == PMONITOR->specialWorkspaceID) {
for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
if (!ls->fadingOut)
ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 1.f;
@@ -2266,6 +2335,11 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
return;
}
if (pWindow->m_bIsFullscreen == on) {
Debug::log(LOG, "Window is already in the required fullscreen state");
return;
}
const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID);
const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID);
@@ -2290,7 +2364,7 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
}
updateFullscreenFadeOnWorkspace(PWORKSPACE);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv(), true);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal(), true);
forceReportSizesToWindowsOnWorkspace(pWindow->m_iWorkspaceID);
@@ -2413,7 +2487,7 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) {
// warpCursorTo should only be used for warps that
// should be disabled with no_cursor_warps
static auto* const PNOWARPS = &g_pConfigManager->getConfigValuePtr("general:no_cursor_warps")->intValue;
static auto PNOWARPS = CConfigValue<Hyprlang::INT>("general:no_cursor_warps");
if (*PNOWARPS && !force)
return;
@@ -2479,7 +2553,7 @@ SLayerSurface* CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) {
// returns a delta
Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, const Vector2D& relativeTo) {
if (!args.contains(' '))
if (!args.contains(' ') && !args.contains('\t'))
return relativeTo;
const auto PMONITOR = m_pLastMonitor;
@@ -2488,12 +2562,13 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
bool yIsPercent = false;
bool isExact = false;
std::string x = args.substr(0, args.find_first_of(' '));
std::string y = args.substr(args.find_first_of(' ') + 1);
CVarList varList(args, 0, 's', true);
std::string x = varList[0];
std::string y = varList[1];
if (x == "exact") {
x = y.substr(0, y.find_first_of(' '));
y = y.substr(y.find_first_of(' ') + 1);
x = varList[1];
y = varList[2];
isExact = true;
}
@@ -2529,7 +2604,7 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con
void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) {
for (auto& w : m_vWindows) {
if (w->m_iWorkspaceID == wid && w->m_bIsMapped && !w->isHidden()) {
g_pXWaylandManager->setWindowSize(w.get(), w->m_vRealSize.vec(), true);
g_pXWaylandManager->setWindowSize(w.get(), w->m_vRealSize.value(), true);
}
}
}
@@ -2545,10 +2620,7 @@ CWorkspace* CCompositor::createNewWorkspace(const int& id, const int& monid, con
const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2;
const auto PWORKSPACE = m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(monID, NAME, SPECIAL)).get();
PWORKSPACE->m_iID = id;
PWORKSPACE->m_iMonitorID = monID;
const auto PWORKSPACE = m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(id, monID, NAME, SPECIAL)).get();
PWORKSPACE->m_fAlpha.setValueAndWarp(0);
@@ -2581,7 +2653,7 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace);
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + PWORKSPACE->m_szName});
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + (PWORKSPACE ? PWORKSPACE->m_szName : "?")});
EMIT_HOOK_EVENT("focusedMon", pMonitor);
m_pLastMonitor = pMonitor;
}
@@ -2619,9 +2691,6 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
pWindow->moveToWorkspace(pWorkspace->m_iID);
pWindow->updateToplevel();
pWindow->updateDynamicRules();
pWindow->uncacheWindowDecos();
if (!pWindow->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow);
@@ -2630,7 +2699,7 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(pWindow);
} else {
const auto PWINDOWMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto POSTOMON = pWindow->m_vRealPosition.goalv() - PWINDOWMONITOR->vecPosition;
const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition;
const auto PWORKSPACEMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
@@ -2640,6 +2709,10 @@ void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorks
pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition;
}
pWindow->updateToplevel();
pWindow->updateDynamicRules();
pWindow->uncacheWindowDecos();
if (pWindow->m_sGroupData.pNextWindow) {
CWindow* next = pWindow->m_sGroupData.pNextWindow;
while (next != pWindow) {
@@ -2678,7 +2751,7 @@ void CCompositor::setIdleActivityInhibit(bool enabled) {
wlr_idle_notifier_v1_set_inhibited(g_pCompositor->m_sWLRIdleNotifier, !enabled);
}
void CCompositor::arrangeMonitors() {
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling");
std::vector<CMonitor*> toArrange;
std::vector<CMonitor*> arranged;
@@ -2746,6 +2819,8 @@ void CCompositor::enterUnsafeState() {
m_pUnsafeOutput->onConnect(false);
m_bUnsafeState = true;
setActiveMonitor(m_pUnsafeOutput);
}
void CCompositor::leaveUnsafeState() {

View File

@@ -21,8 +21,8 @@
#include "debug/HyprDebugOverlay.hpp"
#include "debug/HyprNotificationOverlay.hpp"
#include "helpers/Monitor.hpp"
#include "helpers/Workspace.hpp"
#include "Window.hpp"
#include "desktop/Workspace.hpp"
#include "desktop/Window.hpp"
#include "render/Renderer.hpp"
#include "render/OpenGL.hpp"
#include "hyprerror/HyprError.hpp"
@@ -57,7 +57,6 @@ class CCompositor {
wlr_layer_shell_v1* m_sWLRLayerShell;
wlr_xdg_shell* m_sWLRXDGShell;
wlr_cursor* m_sWLRCursor;
wlr_xcursor_manager* m_sWLRXCursorMgr;
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
wlr_output_manager_v1* m_sWLROutputMgr;
wlr_presentation* m_sWLRPresentation;
@@ -93,9 +92,7 @@ class CCompositor {
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::unique_ptr<CWindow>> m_vWindows;
std::vector<std::unique_ptr<SXDGPopup>> m_vXDGPopups;
std::vector<std::unique_ptr<CWorkspace>> m_vWorkspaces;
std::vector<std::unique_ptr<SSubsurface>> m_vSubsurfaces;
std::vector<CWindow*> m_vWindowsFadingOut;
std::vector<SLayerSurface*> m_vSurfacesFadingOut;
@@ -121,6 +118,7 @@ class CCompositor {
bool m_bUnsafeState = false; // unsafe state is when there is no monitors.
bool m_bNextIsUnsafe = false; // because wlroots
CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state
bool m_bExitTriggered = false; // For exit dispatcher
bool m_bIsShuttingDown = false;
// ------------------------------------------------- //
@@ -135,13 +133,14 @@ class CCompositor {
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
bool windowExists(CWindow*);
bool windowValidMapped(CWindow*);
bool monitorExists(CMonitor*);
CWindow* vectorToWindowUnified(const Vector2D&, uint8_t properties, CWindow* pIgnoreWindow = nullptr);
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);
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
CMonitor* getMonitorFromOutput(wlr_output*);
CWindow* getWindowForPopup(wlr_xdg_popup*);
CMonitor* getRealMonitorFromOutput(wlr_output*);
CWindow* getWindowFromSurface(wlr_surface*);
CWindow* getWindowFromHandle(uint32_t);
CWindow* getWindowFromZWLRHandle(wl_resource*);
@@ -151,7 +150,7 @@ class CCompositor {
CWorkspace* getWorkspaceByString(const std::string&);
void sanityCheckWorkspaces();
void updateWorkspaceWindowDecos(const int&);
int getWindowsOnWorkspace(const int&);
int getWindowsOnWorkspace(const int& id, std::optional<bool> onlyTiled = {});
CWindow* getUrgentWindow();
bool hasUrgentWindowOnWorkspace(const int&);
CWindow* getFirstWindowOnWorkspace(const int&);
@@ -167,8 +166,8 @@ class CCompositor {
int getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
CWindow* getConstraintWindow(SMouse*);
CMonitor* getMonitorInDirection(const char&);
CMonitor* getMonitorInDirection(CMonitor*, const char&);
void updateAllWindowsAnimatedDecorationValues();
void updateWorkspaceWindows(const int64_t& id);
void updateWindowAnimatedDecorationValues(CWindow*);
@@ -177,7 +176,7 @@ class CCompositor {
void swapActiveWorkspaces(CMonitor*, CMonitor*);
CMonitor* getMonitorFromString(const std::string&);
bool workspaceIDOutOfBounds(const int64_t&);
void setWindowFullscreen(CWindow*, bool, eFullscreenMode);
void setWindowFullscreen(CWindow*, bool, eFullscreenMode mode = FULLSCREEN_INVALID);
void updateFullscreenFadeOnWorkspace(CWorkspace*);
CWindow* getX11Parent(CWindow*);
void scheduleFrameForMonitor(CMonitor*);
@@ -234,4 +233,7 @@ inline std::map<std::string, xcb_atom_t> HYPRATOMS = {HYPRATOM("_NET_WM_WINDOW_T
HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"),
HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"),
HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION"),
HYPRATOM("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE")};
HYPRATOM("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"),
HYPRATOM("_NET_SUPPORTING_WM_CHECK"),
HYPRATOM("_NET_WM_NAME"),
HYPRATOM("UTF8_STRING")};

View File

@@ -1,10 +1,12 @@
#pragma once
#include "../defines.hpp"
#include "../helpers/VarList.hpp"
#include <vector>
enum eConfigValueDataTypes {
CVD_TYPE_INVALID = -1,
CVD_TYPE_GRADIENT = 0
CVD_TYPE_GRADIENT = 0,
CVD_TYPE_CSS_VALUE = 1
};
class ICustomConfigValueData {
@@ -12,6 +14,8 @@ class ICustomConfigValueData {
virtual ~ICustomConfigValueData() = 0;
virtual eConfigValueDataTypes getDataType() = 0;
virtual std::string toString() = 0;
};
class CGradientValueData : public ICustomConfigValueData {
@@ -49,4 +53,70 @@ class CGradientValueData : public ICustomConfigValueData {
return true;
}
virtual std::string toString() {
std::string result;
for (auto& c : m_vColors) {
result += std::format("{:x} ", c.getAsHex());
}
result += std::format("{}deg", (int)(m_fAngle * 180.0 / M_PI));
return result;
}
};
class CCssGapData : public ICustomConfigValueData {
public:
CCssGapData() : top(0), right(0), bottom(0), left(0){};
CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global){};
CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal){};
CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : top(top), right(horizontal), bottom(bottom), left(horizontal){};
CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : top(top), right(right), bottom(bottom), left(left){};
/* Css like directions */
int64_t top;
int64_t right;
int64_t bottom;
int64_t left;
void parseGapData(CVarList varlist) {
switch (varlist.size()) {
case 1: {
*this = CCssGapData(std::stoi(varlist[0]));
break;
}
case 2: {
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]));
break;
}
case 3: {
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]), std::stoi(varlist[2]));
break;
}
case 4: {
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]), std::stoi(varlist[2]), std::stoi(varlist[3]));
break;
}
default: {
Debug::log(WARN, "Too many arguments provided for gaps.");
*this = CCssGapData(std::stoi(varlist[0]), std::stoi(varlist[1]), std::stoi(varlist[2]), std::stoi(varlist[3]));
break;
}
}
}
void reset(int64_t global) {
top = global;
right = global;
bottom = global;
left = global;
}
virtual eConfigValueDataTypes getDataType() {
return CVD_TYPE_CSS_VALUE;
}
virtual std::string toString() {
return std::format("{} {} {} {}", top, right, bottom, left);
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,6 @@
#include <optional>
#include <functional>
#include <xf86drmMode.h>
#include "../Window.hpp"
#include "../helpers/WLClasses.hpp"
#include "../helpers/Monitor.hpp"
#include "../helpers/VarList.hpp"
@@ -21,20 +20,14 @@
#include "defaultConfig.hpp"
#include "ConfigDataValues.hpp"
#include <hyprlang.hpp>
#define INITANIMCFG(name) animationConfig[name] = {}
#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]}
#define HANDLE void*
struct SConfigValue {
int64_t intValue = -INT64_MAX;
float floatValue = -__FLT_MAX__;
std::string strValue = "";
Vector2D vecValue = Vector2D(-__FLT_MAX__, -__FLT_MAX__);
std::shared_ptr<ICustomConfigValueData> data;
bool set = false; // used for device configs
};
class CWindow;
struct SWorkspaceRule {
std::string monitor = "";
@@ -43,14 +36,15 @@ struct SWorkspaceRule {
int workspaceId = -1;
bool isDefault = false;
bool isPersistent = false;
std::optional<int64_t> gapsIn;
std::optional<int64_t> gapsOut;
std::optional<CCssGapData> gapsIn;
std::optional<CCssGapData> gapsOut;
std::optional<int64_t> borderSize;
std::optional<int> border;
std::optional<int> rounding;
std::optional<int> decorate;
std::optional<int> shadow;
std::optional<std::string> onCreatedEmptyRunCmd;
std::optional<std::string> defaultName;
std::map<std::string, std::string> layoutopts;
};
@@ -76,7 +70,12 @@ struct SAnimationPropertyConfig {
struct SPluginKeyword {
HANDLE handle = 0;
std::string name = "";
std::function<void(const std::string&, const std::string&)> fn;
Hyprlang::PCONFIGHANDLERFUNC fn = nullptr;
};
struct SPluginVariable {
HANDLE handle = 0;
std::string name = "";
};
struct SExecRequestedRule {
@@ -91,44 +90,37 @@ class CConfigManager {
void tick();
void init();
int getInt(const std::string&);
float getFloat(const std::string&);
Vector2D getVec(const std::string&);
std::string getString(const std::string&);
void setFloat(const std::string&, float);
void setInt(const std::string&, int);
void setVec(const std::string&, Vector2D);
void setString(const std::string&, const std::string&);
int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = "");
float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = "");
Vector2D getDeviceVec(const std::string&, const std::string&, const std::string& fallback = "");
std::string getDeviceString(const std::string&, const std::string&, const std::string& fallback = "");
bool deviceConfigExists(const std::string&);
Hyprlang::CConfigValue* getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback);
bool shouldBlurLS(const std::string&);
SConfigValue* getConfigValuePtr(const std::string&);
SConfigValue* getConfigValuePtrSafe(const std::string&);
void* const* getConfigValuePtr(const std::string&);
Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = "");
void onPluginLoadUnload(const std::string& name, bool load);
static std::string getConfigDir();
static std::string getMainConfigPath();
SMonitorRule getMonitorRuleFor(const std::string&, const std::string& displayName = "");
SWorkspaceRule getWorkspaceRuleFor(CWorkspace*);
SMonitorRule getMonitorRuleFor(const CMonitor&);
std::vector<SWorkspaceRule> getWorkspaceRulesFor(CWorkspace*);
std::string getDefaultWorkspaceFor(const std::string&);
CMonitor* getBoundMonitorForWS(const std::string&);
std::string getBoundMonitorStringForWS(const std::string&);
const std::deque<SWorkspaceRule>& getAllWorkspaceRules();
std::vector<SWindowRule> getMatchingRules(CWindow*);
std::vector<SWindowRule> getMatchingRules(CWindow*, bool dynamic = true, bool shadowExec = false);
std::vector<SLayerRule> getMatchingRules(SLayerSurface*);
std::unordered_map<std::string, SMonitorAdditionalReservedArea> m_mAdditionalReservedAreas;
std::unordered_map<std::string, SAnimationPropertyConfig> getAnimationConfig();
void addPluginConfigVar(HANDLE handle, const std::string& name, const SConfigValue& value);
void addPluginKeyword(HANDLE handle, const std::string& name, std::function<void(const std::string& cmd, const std::string& val)> fun);
void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value);
void addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fun, Hyprlang::SHandlerOptions opts = {});
void removePluginConfig(HANDLE handle);
// no-op when done.
@@ -141,7 +133,7 @@ class CConfigManager {
void ensureMonitorStatus();
void ensureVRR(CMonitor* pMonitor = nullptr);
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
std::string parseKeyword(const std::string&, const std::string&);
void addParseError(const std::string&);
@@ -150,29 +142,44 @@ class CConfigManager {
void addExecRule(const SExecRequestedRule&);
void handlePluginLoads();
std::string getErrors();
// keywords
std::optional<std::string> handleRawExec(const std::string&, const std::string&);
std::optional<std::string> handleExecOnce(const std::string&, const std::string&);
std::optional<std::string> handleMonitor(const std::string&, const std::string&);
std::optional<std::string> handleBind(const std::string&, const std::string&);
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
std::optional<std::string> handleBezier(const std::string&, const std::string&);
std::optional<std::string> handleAnimation(const std::string&, const std::string&);
std::optional<std::string> handleSource(const std::string&, const std::string&);
std::optional<std::string> handleSubmap(const std::string&, const std::string&);
std::optional<std::string> handleBlurLS(const std::string&, const std::string&);
std::optional<std::string> handleBindWS(const std::string&, const std::string&);
std::optional<std::string> handleEnv(const std::string&, const std::string&);
std::optional<std::string> handlePlugin(const std::string&, const std::string&);
std::string configCurrentPath;
private:
std::unique_ptr<Hyprlang::CConfig> m_pConfig;
std::deque<std::string> configPaths; // stores all the config paths
std::unordered_map<std::string, time_t> configModifyTimes; // stores modify times
std::vector<std::pair<std::string, std::string>> configDynamicVars; // stores dynamic vars declared by the user
std::unordered_map<std::string, SConfigValue> configValues;
std::unordered_map<std::string, std::unordered_map<std::string, SConfigValue>> deviceConfigs; // stores device configs
std::unordered_map<std::string, SAnimationPropertyConfig> animationConfig; // stores all the animations with their set values
std::string currentCategory = ""; // For storing the category of the current item
std::string parseError = ""; // For storing a parse error to display later
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
std::vector<SExecRequestedRule> execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty
std::vector<std::string> m_vDeclaredPlugins;
std::unordered_map<HANDLE, std::unique_ptr<std::unordered_map<std::string, SConfigValue>>> pluginConfigs; // stores plugin configs
std::vector<SPluginKeyword> pluginKeywords;
std::vector<SPluginVariable> pluginVariables;
bool isFirstLaunch = true; // For exec-once
@@ -186,42 +193,17 @@ class CConfigManager {
bool m_bManualCrashInitiated = false;
std::deque<std::string> firstExecRequests;
std::vector<std::pair<std::string, std::string>> environmentVariables;
std::vector<std::pair<std::string, std::string>> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins
std::string m_szConfigErrors = "";
// internal methods
void setDefaultVars();
void setDefaultAnimationVars();
void setDeviceDefaultVars(const std::string&);
void populateEnvironment();
void setAnimForChildren(SAnimationPropertyConfig* const);
void updateBlurredLS(const std::string&, const bool);
void applyUserDefinedVars(std::string&, const size_t);
void loadConfigLoadVars();
SConfigValue getConfigValueSafe(const std::string&);
SConfigValue getConfigValueSafeDevice(const std::string&, const std::string&, const std::string& fallback = "");
void parseLine(std::string&);
void configSetValueSafe(const std::string&, const std::string&);
void handleDeviceConfig(const std::string&, const std::string&);
void handleRawExec(const std::string&, const std::string&);
void handleMonitor(const std::string&, const std::string&);
void handleBind(const std::string&, const std::string&);
void handleUnbind(const std::string&, const std::string&);
void handleWindowRule(const std::string&, const std::string&);
void handleLayerRule(const std::string&, const std::string&);
void handleWindowRuleV2(const std::string&, const std::string&);
void handleWorkspaceRules(const std::string&, const std::string&);
void handleBezier(const std::string&, const std::string&);
void handleAnimation(const std::string&, const std::string&);
void handleSource(const std::string&, const std::string&);
void handleSubmap(const std::string&, const std::string&);
void handleBlurLS(const std::string&, const std::string&);
void handleBindWS(const std::string&, const std::string&);
void handleEnv(const std::string&, const std::string&);
void handlePlugin(const std::string&, const std::string&);
void setDefaultAnimationVars();
std::optional<std::string> resetHLConfig();
std::optional<std::string> verifyConfigExists();
void postConfigReload(const Hyprlang::CParseResult& result);
void reload();
};
inline std::unique_ptr<CConfigManager> g_pConfigManager;

View File

@@ -0,0 +1,72 @@
#pragma once
#include <string>
#include <typeindex>
#include <hyprlang.hpp>
#include "../debug/Log.hpp"
#include "../macros.hpp"
template <typename T>
class CConfigValue {
public:
CConfigValue(const std::string& val) {
const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val.c_str());
p_ = PVHYPRLANG->getDataStaticPtr();
#ifdef HYPRLAND_DEBUG
// verify type
const auto ANY = PVHYPRLANG->getValue();
const auto TYPE = std::type_index(ANY.type());
// exceptions
const bool STRINGEX = (typeid(T) == typeid(std::string) && TYPE == typeid(Hyprlang::STRING));
const bool CUSTOMEX = (typeid(T) == typeid(Hyprlang::CUSTOMTYPE) && (TYPE == typeid(Hyprlang::CUSTOMTYPE*) || TYPE == typeid(void*) /* dunno why it does this? */));
RASSERT(typeid(T) == TYPE || STRINGEX || CUSTOMEX, "Mismatched type in CConfigValue<T>, got {} but has {}", typeid(T).name(), TYPE.name());
#endif
}
T* ptr() const {
return *(T* const*)p_;
}
T operator*() const {
return *ptr();
}
private:
void* const* p_ = nullptr;
};
template <>
inline std::string* CConfigValue<std::string>::ptr() const {
RASSERT(false, "Impossible to implement ptr() of CConfigValue<std::string>");
return nullptr;
}
template <>
inline std::string CConfigValue<std::string>::operator*() const {
return std::string{*(Hyprlang::STRING*)p_};
}
template <>
inline Hyprlang::STRING* CConfigValue<Hyprlang::STRING>::ptr() const {
return (Hyprlang::STRING*)p_;
}
template <>
inline Hyprlang::STRING CConfigValue<Hyprlang::STRING>::operator*() const {
return *(Hyprlang::STRING*)p_;
}
template <>
inline Hyprlang::CUSTOMTYPE* CConfigValue<Hyprlang::CUSTOMTYPE>::ptr() const {
return *(Hyprlang::CUSTOMTYPE* const*)p_;
}
template <>
inline Hyprlang::CUSTOMTYPE CConfigValue<Hyprlang::CUSTOMTYPE>::operator*() const {
RASSERT(false, "Impossible to implement operator* of CConfigValue<Hyprlang::CUSTOMTYPE>, use ptr()");
return *ptr();
}

View File

@@ -3,11 +3,11 @@
#include <string>
inline const std::string AUTOCONFIG = R"#(
########################################################################################
AUTOGENERATED HYPR CONFIG.
PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
########################################################################################
# #######################################################################################
# AUTOGENERATED HYPR CONFIG.
# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT,
# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS.
# #######################################################################################
#
# Please note not all available settings / options are set here.
@@ -51,7 +51,7 @@ input {
natural_scroll = no
}
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
sensitivity = 0 # -1.0 to 1.0, 0 means no modification.
}
general {
@@ -123,8 +123,9 @@ misc {
}
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#executing for more
device:epic-mouse-v1 {
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
device {
name = epic-mouse-v1
sensitivity = -0.5
}
@@ -133,7 +134,7 @@ device:epic-mouse-v1 {
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
windowrulev2 = nomaximizerequest, class:.* # You'll probably like this.
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
# See https://wiki.hyprland.org/Configuring/Keywords/ for more

View File

@@ -3,6 +3,7 @@
#include <sys/utsname.h>
#include <fstream>
#include <signal.h>
#include <link.h>
#include "../plugins/PluginSystem.hpp"
@@ -105,16 +106,38 @@ void CrashReporter::createAndSaveCrash(int sig) {
const auto FPATH = std::filesystem::canonical("/proc/self/exe");
#endif
std::string addrs = "";
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
finalCrashReport += std::format("\t#{} | {}\n", i, CALLSTACK[i].desc);
#ifdef __clang__
const auto CMD = std::format("llvm-addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
#ifdef __GLIBC__
// convert in memory address to VMA address
Dl_info info;
struct link_map* linkMap;
dladdr1((void*)CALLSTACK[i].adr, &info, (void**)&linkMap, RTLD_DL_LINKMAP);
size_t vmaAddr = (size_t)CALLSTACK[i].adr - linkMap->l_addr;
#else
const auto CMD = std::format("addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
// musl doesn't define dladdr1
size_t vmaAddr = (size_t)CALLSTACK[i].adr;
#endif
const auto ADDR2LINE = replaceInString(execAndGet(CMD.c_str()), "\n", "\n\t\t");
finalCrashReport += "\t\t" + ADDR2LINE.substr(0, ADDR2LINE.length() - 2);
addrs += std::format("0x{:x} ", vmaAddr);
}
#ifdef __clang__
const auto CMD = std::format("llvm-addr2line -e {} -Cf {}", FPATH.c_str(), addrs);
#else
const auto CMD = std::format("addr2line -e {} -Cf {}", FPATH.c_str(), addrs);
#endif
const auto ADDR2LINE = execAndGet(CMD.c_str());
std::stringstream ssin(ADDR2LINE);
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
finalCrashReport += std::format("\t#{} | {}", i, CALLSTACK[i].desc);
std::string functionInfo;
std::string fileLineInfo;
std::getline(ssin, functionInfo);
std::getline(ssin, fileLineInfo);
finalCrashReport += std::format("\n\t\t{}\n\t\t{}\n", functionInfo, fileLineInfo);
}
finalCrashReport += "\n\nLog tail:\n";
@@ -128,22 +151,19 @@ void CrashReporter::createAndSaveCrash(int sig) {
return;
std::ofstream ofs;
std::string path;
if (!CACHE_HOME || std::string(CACHE_HOME).empty()) {
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland"))
std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
std::string reportDir;
if (!CACHE_HOME || std::string(CACHE_HOME).empty())
reportDir = std::string(HOME) + "/.cache/hyprland";
else
reportDir = std::string(CACHE_HOME) + "/hyprland";
if (!std::filesystem::exists(reportDir))
std::filesystem::create_directory(reportDir);
const auto path = reportDir + "/hyprlandCrashReport" + std::to_string(PID) + ".txt";
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc);
} else {
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland"))
std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
ofs.open(path, std::ios::trunc);
}
ofs << finalCrashReport;
ofs.close();

View File

@@ -10,10 +10,14 @@
#include <sys/utsname.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <sstream>
#include <string>
#include <typeindex>
#include "../config/ConfigValue.hpp"
#include "../managers/CursorManager.hpp"
#include "../hyprerror/HyprError.hpp"
static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',')
@@ -29,6 +33,38 @@ static std::string getWorkspaceNameFromSpecialID(const int workspaceID) {
return workspace->m_szName;
}
static std::string formatToString(uint32_t drmFormat) {
switch (drmFormat) {
case DRM_FORMAT_XRGB2101010: return "XRGB2101010";
case DRM_FORMAT_XBGR2101010: return "XBGR2101010";
case DRM_FORMAT_XRGB8888: return "XRGB8888";
case DRM_FORMAT_XBGR8888: return "XBGR8888";
default: break;
}
return "Invalid";
}
static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) {
std::string result;
if (!wl_list_empty(&pMonitor->output->modes)) {
wlr_output_mode* mode;
wl_list_for_each(mode, &pMonitor->output->modes, link) {
if (format == FORMAT_NORMAL)
result += std::format("{}x{}@{:.2f}Hz ", mode->width, mode->height, mode->refresh / 1000.0);
else
result += std::format("\"{}x{}@{:.2f}Hz\",", mode->width, mode->height, mode->refresh / 1000.0);
}
result.pop_back();
}
return result;
}
std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
auto allMonitors = false;
@@ -74,15 +110,17 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
"focused": {},
"dpmsStatus": {},
"vrr": {},
"activelyTearing": {}
"activelyTearing": {},
"currentFormat": "{}",
"availableModes": [{}]
}},)#",
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szDescription), (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->activeWorkspace, (m->activeWorkspace == -1 ? "" : escapeJSONStrings(g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName)), m->specialWorkspaceID,
escapeJSONStrings(getWorkspaceNameFromSpecialID(m->specialWorkspaceID)), (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"),
(m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"),
m->tearingState.activelyTearing ? "true" : "false");
m->tearingState.activelyTearing ? "true" : "false", formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
}
trimTrailingComma(result);
@@ -97,13 +135,14 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial "
"workspace: {} ({})\n\treserved: {} "
"{} {} {}\n\tscale: {:.2f}\n\ttransform: "
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\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->szDescription,
"{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspace,
(m->activeWorkspace == -1 ? "" : g_pCompositor->getWorkspaceByID(m->activeWorkspace)->m_szName), m->specialWorkspaceID,
getWorkspaceNameFromSpecialID(m->specialWorkspaceID), (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 ? "yes" : "no"), (int)m->dpmsStatus,
(int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing);
(int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing, formatToString(m->drmFormat),
availableModesForOutput(m.get(), format));
}
}
@@ -171,8 +210,8 @@ static std::string getWindowData(CWindow* w, eHyprCtlOutputFormat format) {
"swallowing": "0x{:x}",
"focusHistoryID": {}
}},)#",
(uintptr_t)w, (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y,
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID,
(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,
escapeJSONStrings(w->m_iWorkspaceID == -1 ? "" :
g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName :
std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))),
@@ -187,8 +226,8 @@ static std::string getWindowData(CWindow* w, eHyprCtlOutputFormat format) {
"{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: "
"{}\n\txwayland: {}\n\tpinned: "
"{}\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.goalv().x, (int)w->m_vRealPosition.goalv().y,
(int)w->m_vRealSize.goalv().x, (int)w->m_vRealSize.goalv().y, w->m_iWorkspaceID,
(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,
(int)w->m_vRealSize.goal().y, w->m_iWorkspaceID,
(w->m_iWorkspaceID == -1 ? "" :
g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_szName :
std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID))),
@@ -205,6 +244,9 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
result += "[";
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all)
continue;
result += getWindowData(w.get(), format);
}
@@ -213,6 +255,9 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
result += "]";
} else {
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all)
continue;
result += getWindowData(w.get(), format);
}
}
@@ -249,8 +294,12 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor));
const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : "";
const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : "";
const std::string gapsIn = (bool)(r.gapsIn) ? std::format(",\n \"gapsIn\": {}", r.gapsIn.value()) : "";
const std::string gapsOut = (bool)(r.gapsOut) ? std::format(",\n \"gapsOut\": {}", r.gapsOut.value()) : "";
const std::string gapsIn = (bool)(r.gapsIn) ?
std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().top, r.gapsIn.value().right, r.gapsIn.value().bottom, r.gapsIn.value().left) :
"";
const std::string gapsOut = (bool)(r.gapsOut) ?
std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) :
"";
const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : "";
const std::string border = (bool)(r.border) ? std::format(",\n \"border\": {}", boolToString(r.border.value())) : "";
const std::string rounding = (bool)(r.rounding) ? std::format(",\n \"rounding\": {}", boolToString(r.rounding.value())) : "";
@@ -267,8 +316,12 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF
const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "<unset>" : escapeJSONStrings(r.monitor));
const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : "<unset>");
const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : "<unset>");
const std::string gapsIn = std::format("\tgapsIn: {}\n", (bool)(r.gapsIn) ? std::to_string(r.gapsIn.value()) : "<unset>");
const std::string gapsOut = std::format("\tgapsOut: {}\n", (bool)(r.gapsOut) ? std::to_string(r.gapsOut.value()) : "<unset>");
const std::string gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().top), std::to_string(r.gapsIn.value().right),
std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) :
std::format("\tgapsIn: <unset>\n");
const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().top), std::to_string(r.gapsOut.value().right),
std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) :
std::format("\tgapsOut: <unset>\n");
const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : "<unset>");
const std::string border = std::format("\tborder: {}\n", (bool)(r.border) ? boolToString(r.border.value()) : "<unset>");
const std::string rounding = std::format("\trounding: {}\n", (bool)(r.rounding) ? boolToString(r.rounding.value()) : "<unset>");
@@ -445,6 +498,29 @@ std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
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 result = "";
@@ -581,7 +657,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
}
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) {
@@ -710,8 +786,8 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
if (kb.nonConsuming)
ret += "n";
ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, kb.key, kb.keycode, kb.handler,
kb.arg);
ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, kb.key,
kb.keycode, kb.catchAll, kb.handler, kb.arg);
}
} else {
// json
@@ -729,11 +805,13 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
"submap": "{}",
"key": "{}",
"keycode": {},
"catch_all": {},
"dispatcher": "{}",
"arg": "{}"
}},)#",
kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false",
kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg));
kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", escapeJSONStrings(kb.handler),
escapeJSONStrings(kb.arg));
}
trimTrailingComma(ret);
ret += "]";
@@ -856,32 +934,35 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
const auto VALUE = in.substr(in.find_first_of(' ') + 1);
std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE, true);
std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE);
if (COMMAND == "monitor")
// if we are executing a dynamic source we have to reload everything, so every if will have a check for source.
if (COMMAND == "monitor" || COMMAND == "source")
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords
if (COMMAND.contains("input") || COMMAND.contains("device:")) {
if (COMMAND.contains("input") || COMMAND.contains("device") || COMMAND == "source") {
g_pInputManager->setKeyboardLayout(); // update kb layout
g_pInputManager->setPointerConfigs(); // update mouse cfgs
g_pInputManager->setTouchDeviceConfigs(); // update touch device cfgs
g_pInputManager->setTabletConfigs(); // update tablets
}
if (COMMAND.contains("general:layout"))
g_pLayoutManager->switchToLayout(g_pConfigManager->getString("general:layout")); // update layout
static auto PLAYOUT = CConfigValue<std::string>("general:layout");
if (COMMAND.contains("decoration:screen_shader"))
if (COMMAND.contains("general:layout"))
g_pLayoutManager->switchToLayout(*PLAYOUT); // update layout
if (COMMAND.contains("decoration:screen_shader") || COMMAND == "source")
g_pHyprOpenGL->m_bReloadScreenShader = true;
if (COMMAND.contains("blur")) {
if (COMMAND.contains("blur") || COMMAND == "source") {
for (auto& [m, rd] : g_pHyprOpenGL->m_mMonitorRenderResources) {
rd.blurFBDirty = true;
}
}
// decorations will probably need a repaint
if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("cursor_zoom_factor")) {
if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("cursor_zoom_factor") || COMMAND == "source") {
for (auto& m : g_pCompositor->m_vMonitors) {
g_pHyprRenderer->damageMonitor(m.get());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
@@ -962,7 +1043,7 @@ std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
nextItem();
while (curitem != "") {
while (curitem != "" || request != "") {
reply += g_pHyprCtl->getReply(curitem);
nextItem();
@@ -989,16 +1070,7 @@ std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request)
if (size <= 0)
return "size not positive";
wlr_xcursor_manager_destroy(g_pCompositor->m_sWLRXCursorMgr);
g_pCompositor->m_sWLRXCursorMgr = wlr_xcursor_manager_create(theme.c_str(), size);
setenv("XCURSOR_SIZE", SIZESTR.c_str(), true);
setenv("XCURSOR_THEME", theme.c_str(), true);
for (auto& m : g_pCompositor->m_vMonitors) {
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, m->scale);
}
g_pCursorManager->changeTheme(theme, size);
return "ok";
}
@@ -1084,6 +1156,7 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
if (vars.size() < 4)
return "not enough args";
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
if (!PWINDOW)
@@ -1092,13 +1165,12 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
const auto PROP = vars[2];
const auto VAL = vars[3];
auto noFocus = PWINDOW->m_sAdditionalConfigData.noFocus;
bool lock = false;
if (vars.size() > 4) {
if (vars[4].starts_with("lock")) {
if (request.ends_with("lock"))
lock = true;
}
}
try {
if (PROP == "animationstyle") {
@@ -1121,10 +1193,28 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
PWINDOW->m_sAdditionalConfigData.forceNoShadow.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenodim") {
PWINDOW->m_sAdditionalConfigData.forceNoDim.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nofocus") {
PWINDOW->m_sAdditionalConfigData.noFocus.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "windowdancecompat") {
PWINDOW->m_sAdditionalConfigData.windowDanceCompat.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "nomaxsize") {
PWINDOW->m_sAdditionalConfigData.noMaxSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "maxsize") {
PWINDOW->m_sAdditionalConfigData.maxSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock);
if (lock) {
PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x),
std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
PWINDOW->setHidden(false);
}
} else if (PROP == "minsize") {
PWINDOW->m_sAdditionalConfigData.minSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock);
if (lock) {
PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x),
std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
PWINDOW->setHidden(false);
}
} else if (PROP == "dimaround") {
PWINDOW->m_sAdditionalConfigData.dimAround.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "alphaoverride") {
@@ -1156,6 +1246,12 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
if (!(PWINDOW->m_sAdditionalConfigData.noFocus.toUnderlying() == noFocus.toUnderlying())) {
g_pCompositor->focusWindow(nullptr);
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->focusWindow(PLASTWINDOW);
}
for (auto& m : g_pCompositor->m_vMonitors)
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
@@ -1182,28 +1278,41 @@ std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request)
nextItem();
nextItem();
const auto PCFGOPT = g_pConfigManager->getConfigValuePtrSafe(curitem);
const auto VAR = g_pConfigManager->getHyprlangConfigValuePtr(curitem);
if (!PCFGOPT)
if (!VAR)
return "no such option";
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL)
return std::format("option {}\n\tint: {}\n\tfloat: {:.5f}\n\tstr: \"{}\"\n\tdata: {:x}\n\tset: {}", curitem, PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue,
(uintptr_t)PCFGOPT->data.get(), PCFGOPT->set);
else {
return std::format(
R"#(
{{
"option": "{}",
"int": {},
"float": {:.5f},
"str": "{}",
"data": "0x{:x}",
"set": {}
}}
)#",
curitem, PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue, (uintptr_t)PCFGOPT->data.get(), PCFGOPT->set);
const auto VAL = VAR->getValue();
const auto TYPE = std::type_index(VAL.type());
if (format == FORMAT_NORMAL) {
if (TYPE == typeid(Hyprlang::INT))
return std::format("int: {}\nset: {}", std::any_cast<Hyprlang::INT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::FLOAT))
return std::format("float: {:2f}\nset: {}", std::any_cast<Hyprlang::FLOAT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::VEC2))
return std::format("vec2: [{}, {}]\nset: {}", std::any_cast<Hyprlang::VEC2>(VAL).x, std::any_cast<Hyprlang::VEC2>(VAL).y, VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::STRING))
return std::format("str: {}\nset: {}", std::any_cast<Hyprlang::STRING>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(void*))
return std::format("custom type: {}\nset: {}", ((ICustomConfigValueData*)std::any_cast<void*>(VAL))->toString(), VAR->m_bSetByUser);
} else {
if (TYPE == typeid(Hyprlang::INT))
return std::format("{{\"option\": \"{}\", \"int\": {}, \"set\": {} }}", curitem, std::any_cast<Hyprlang::INT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::FLOAT))
return std::format("{{\"option\": \"{}\", \"float\": {:2f}, \"set\": {} }}", curitem, std::any_cast<Hyprlang::FLOAT>(VAL), VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::VEC2))
return std::format("{{\"option\": \"{}\", \"vec2\": [{},{}], \"set\": {} }}", curitem, std::any_cast<Hyprlang::VEC2>(VAL).x, std::any_cast<Hyprlang::VEC2>(VAL).y,
VAR->m_bSetByUser);
else if (TYPE == typeid(Hyprlang::STRING))
return std::format("{{\"option\": \"{}\", \"str\": \"{}\", \"set\": {} }}", curitem, escapeJSONStrings(std::any_cast<Hyprlang::STRING>(VAL)), VAR->m_bSetByUser);
else if (TYPE == typeid(void*))
return std::format("{{\"option\": \"{}\", \"custom\": \"{}\", \"set\": {} }}", curitem, ((ICustomConfigValueData*)std::any_cast<void*>(VAL))->toString(),
VAR->m_bSetByUser);
}
return "invalid type (internal error)";
}
std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) {
@@ -1342,6 +1451,9 @@ std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
} else if (OPERATION == "list") {
const auto PLUGINS = g_pPluginSystem->getAllPlugins();
if (PLUGINS.size() == 0)
return "no plugins loaded";
std::string list = "";
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);
@@ -1383,15 +1495,47 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
CColor color = configStringToInt(vars[3]);
std::string message = "";
size_t msgidx = 4;
float fontsize = 13.f;
if (vars[msgidx].length() > 9 && vars[msgidx].compare(0, 9, "fontsize:") == 0) {
const auto FONTSIZE = vars[msgidx].substr(9);
for (size_t i = 4; i < vars.size(); ++i) {
message += vars[i] + " ";
if (!isNumber(FONTSIZE, true))
return "invalid fontsize kwarg";
try {
fontsize = std::stoi(FONTSIZE);
} catch (std::exception& e) { return "invalid fontsize karg"; }
++msgidx;
}
message.pop_back();
if (vars.size() <= msgidx)
return "not enough args";
g_pHyprNotificationOverlay->addNotification(message, color, time, (eIcons)icon);
const auto MESSAGE = vars.join(" ", msgidx);
g_pHyprNotificationOverlay->addNotification(MESSAGE, color, time, (eIcons)icon, fontsize);
return "ok";
}
std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
int amount = -1;
if (vars.size() > 1) {
const auto AMOUNT = vars[1];
if (!isNumber(AMOUNT))
return "invalid arg 1";
try {
amount = std::stoi(AMOUNT);
} catch (std::exception& e) { return "invalid arg 1"; }
}
g_pHyprNotificationOverlay->dismissNotifications(amount);
return "ok";
}
@@ -1414,11 +1558,13 @@ CHyprCtl::CHyprCtl() {
registerCommand(SHyprCtlCommand{"animations", true, animationsRequest});
registerCommand(SHyprCtlCommand{"rollinglog", true, rollinglogRequest});
registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest});
registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest});
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
registerCommand(SHyprCtlCommand{"plugin", false, dispatchPlugin});
registerCommand(SHyprCtlCommand{"notify", false, dispatchNotify});
registerCommand(SHyprCtlCommand{"dismissnotify", false, dispatchDismissNotify});
registerCommand(SHyprCtlCommand{"setprop", false, dispatchSetProp});
registerCommand(SHyprCtlCommand{"seterror", false, dispatchSeterror});
registerCommand(SHyprCtlCommand{"switchxkblayout", false, switchXKBLayoutRequest});
@@ -1443,6 +1589,8 @@ void CHyprCtl::unregisterCommand(const std::shared_ptr<SHyprCtlCommand>& cmd) {
std::string CHyprCtl::getReply(std::string request) {
auto format = eHyprCtlOutputFormat::FORMAT_NORMAL;
bool reloadAll = false;
m_sCurrentRequestParams = {};
// process flags for non-batch requests
if (!request.starts_with("[[BATCH]]") && request.contains("/")) {
@@ -1463,30 +1611,68 @@ std::string CHyprCtl::getReply(std::string request) {
if (c == 'j')
format = eHyprCtlOutputFormat::FORMAT_JSON;
else if (c == 'r')
reloadAll = true;
else if (c == 'a')
m_sCurrentRequestParams.all = true;
}
if (sepIndex < request.size())
request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string
}
std::string result = "";
// parse exact cmds first, then non-exact.
for (auto& cmd : m_vCommands) {
if (!cmd->exact)
continue;
if (cmd->name == request)
return cmd->fn(format, request);
if (cmd->name == request) {
result = cmd->fn(format, request);
break;
}
}
if (result.empty())
for (auto& cmd : m_vCommands) {
if (cmd->exact)
continue;
if (request.starts_with(cmd->name))
return cmd->fn(format, request);
if (request.starts_with(cmd->name)) {
result = cmd->fn(format, request);
break;
}
}
if (result.empty())
return "unknown request";
if (reloadAll) {
g_pConfigManager->m_bWantsMonitorReload = true; // for monitor keywords
g_pInputManager->setKeyboardLayout(); // update kb layout
g_pInputManager->setPointerConfigs(); // update mouse cfgs
g_pInputManager->setTouchDeviceConfigs(); // update touch device cfgs
g_pInputManager->setTabletConfigs(); // update tablets
static auto PLAYOUT = CConfigValue<std::string>("general:layout");
g_pLayoutManager->switchToLayout(*PLAYOUT); // update layout
g_pHyprOpenGL->m_bReloadScreenShader = true;
for (auto& [m, rd] : g_pHyprOpenGL->m_mMonitorRenderResources) {
rd.blurFBDirty = true;
}
for (auto& m : g_pCompositor->m_vMonitors) {
g_pHyprRenderer->damageMonitor(m.get());
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID);
}
}
return result;
}
std::string CHyprCtl::makeDynamicCall(const std::string& input) {

View File

@@ -16,6 +16,10 @@ class CHyprCtl {
int m_iSocketFD = -1;
struct {
bool all = false;
} m_sCurrentRequestParams;
private:
void startHyprCtlSocket();

View File

@@ -36,7 +36,7 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() {
m_szIconFontName = fonts.substr(COLON + 2, LASTCHAR - (COLON + 2));
}
void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon) {
void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) {
const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique<SNotification>()).get();
PNOTIF->text = text;
@@ -44,12 +44,25 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC
PNOTIF->started.reset();
PNOTIF->timeMs = timeMs;
PNOTIF->icon = icon;
PNOTIF->fontSize = fontSize;
for (auto& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m.get());
}
}
void CHyprNotificationOverlay::dismissNotifications(const int amount) {
if (amount == -1)
m_dNotifications.clear();
else {
const int AMT = std::min(amount, static_cast<int>(m_dNotifications.size()));
for (int i = 0; i < AMT; ++i) {
m_dNotifications.pop_front();
}
}
}
CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
static constexpr auto ANIM_DURATION_MS = 600.0;
static constexpr auto ANIM_LAG_MS = 100.0;
@@ -62,27 +75,24 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
float maxWidth = 0;
const auto SCALE = pMonitor->scale;
const auto FONTSIZE = std::clamp((int)(13.f * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
const auto MONSIZE = pMonitor->vecPixelSize;
cairo_text_extents_t cairoExtents;
int iconW = 0, iconH = 0;
PangoLayout* pangoLayout;
PangoFontDescription* pangoFD;
pangoLayout = pango_cairo_create_layout(m_pCairo);
pangoFD = pango_font_description_from_string(("Sans " + std::to_string(FONTSIZE * ICON_SCALE)).c_str());
pango_layout_set_font_description(pangoLayout, pangoFD);
cairo_select_font_face(m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(m_pCairo, FONTSIZE);
const auto PBEZIER = g_pAnimationManager->getBezier("default");
for (auto& notif : m_dNotifications) {
const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD;
const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40);
PangoLayout* pangoLayout = pango_cairo_create_layout(m_pCairo);
PangoFontDescription* pangoFD = pango_font_description_from_string(("Sans " + std::to_string(FONTSIZE * ICON_SCALE)).c_str());
pango_layout_set_font_description(pangoLayout, pangoFD);
cairo_set_font_size(m_pCairo, FONTSIZE);
// first rect (bg, col)
const float FIRSTRECTANIMP =
@@ -162,10 +172,10 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) {
if (maxWidth < NOTIFSIZE.x)
maxWidth = NOTIFSIZE.x;
}
pango_font_description_free(pangoFD);
g_object_unref(pangoLayout);
}
// cleanup notifs
std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; });
@@ -227,3 +237,7 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) {
CBox pMonBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f);
}
bool CHyprNotificationOverlay::hasAny() {
return !m_dNotifications.empty();
}

View File

@@ -33,6 +33,7 @@ struct SNotification {
CTimer started;
float timeMs = 0;
eIcons icon = ICON_NONE;
float fontSize = 13.f;
};
class CHyprNotificationOverlay {
@@ -40,7 +41,9 @@ class CHyprNotificationOverlay {
CHyprNotificationOverlay();
void draw(CMonitor* pMonitor);
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f);
void dismissNotifications(const int amount);
bool hasAny();
private:
CBox drawNotifications(CMonitor* pMonitor);

View File

@@ -22,7 +22,7 @@ void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
rollingLog += output + "\n";
if (!disableLogs || !*disableLogs) {
if (!disableLogs || !**disableLogs) {
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);
ofs << "[wlr] " << output << "\n";

View File

@@ -22,8 +22,8 @@ enum LogLevel {
namespace Debug {
inline std::string logFile;
inline int64_t* disableLogs = nullptr;
inline int64_t* disableTime = nullptr;
inline int64_t* const* disableLogs = nullptr;
inline int64_t* const* disableTime = nullptr;
inline bool disableStdout = false;
inline bool trace = false;
inline bool shuttingDown = false;
@@ -52,7 +52,7 @@ namespace Debug {
}
// print date and time to the ofs
if (disableTime && !*disableTime) {
if (disableTime && !**disableTime) {
#ifndef _LIBCPP_VERSION
logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor<std::chrono::days>(std::chrono::system_clock::now())});
#else
@@ -73,7 +73,7 @@ namespace Debug {
if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
if (!disableLogs || !*disableLogs) {
if (!disableLogs || !**disableLogs) {
// log to a file
std::ofstream ofs;
ofs.open(logFile, std::ios::out | std::ios::app);

128
src/desktop/Constraint.cpp Normal file
View File

@@ -0,0 +1,128 @@
#include "Constraint.hpp"
#include "WLSurface.hpp"
#include "../Compositor.hpp"
CConstraint::CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner) : m_pOwner(owner), m_pConstraint(constraint) {
initSignals();
m_vCursorPosOnActivate = g_pInputManager->getMouseCoordsInternal();
g_pInputManager->m_vConstraints.push_back(this);
if (g_pCompositor->m_pLastFocus == m_pOwner->wlr())
activate();
}
CConstraint::~CConstraint() {
std::erase(g_pInputManager->m_vConstraints, this);
}
static void onConstraintDestroy(void* owner, void* data) {
const auto CONSTRAINT = (CConstraint*)owner;
CONSTRAINT->onDestroy();
}
static void onConstraintSetRegion(void* owner, void* data) {
const auto CONSTRAINT = (CConstraint*)owner;
CONSTRAINT->onSetRegion();
}
void CConstraint::initSignals() {
hyprListener_setConstraintRegion.initCallback(&m_pConstraint->events.set_region, ::onConstraintSetRegion, this, "CConstraint");
hyprListener_destroyConstraint.initCallback(&m_pConstraint->events.destroy, ::onConstraintDestroy, this, "CConstraint");
}
void CConstraint::onDestroy() {
hyprListener_setConstraintRegion.removeCallback();
hyprListener_destroyConstraint.removeCallback();
if (active() && isLocked())
g_pCompositor->warpCursorTo(logicPositionHint(), true);
// this is us
m_pOwner->m_pConstraint.reset();
}
void CConstraint::onSetRegion() {
if (!m_bActive)
return;
m_rRegion.set(&m_pConstraint->region);
m_vPositionHint = m_rRegion.closestPoint(m_vPositionHint);
g_pInputManager->simulateMouseMovement(); // to warp the cursor if anything's amiss
}
void CConstraint::onCommit() {
if (!m_bActive)
return;
const auto COMMITTED = m_pConstraint->current.committed;
if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT) {
m_bHintSet = true;
m_vPositionHint = {m_pConstraint->current.cursor_hint.x, m_pConstraint->current.cursor_hint.y};
g_pInputManager->simulateMouseMovement();
}
if (COMMITTED & WLR_POINTER_CONSTRAINT_V1_STATE_REGION)
onSetRegion();
}
CRegion CConstraint::logicConstraintRegion() {
CRegion rg = m_rRegion;
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{};
rg.translate(CONSTRAINTPOS);
return rg;
}
CWLSurface* CConstraint::owner() {
return m_pOwner;
}
bool CConstraint::isLocked() {
return m_pConstraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED;
}
Vector2D CConstraint::logicPositionHint() {
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{};
return m_bHintSet ? CONSTRAINTPOS + m_vPositionHint : m_vCursorPosOnActivate;
}
void CConstraint::deactivate() {
if (!m_bActive)
return;
m_bActive = false;
wlr_pointer_constraint_v1_send_deactivated(m_pConstraint);
if (isLocked())
g_pCompositor->warpCursorTo(logicPositionHint(), true);
if (m_pConstraint->lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT)
m_bDead = true;
}
void CConstraint::activate() {
if (m_bActive || m_bDead)
return;
m_bActive = true;
// TODO: hack, probably not a super duper great idea
if (g_pCompositor->m_sSeat.seat->pointer_state.focused_surface != m_pOwner->wlr()) {
const auto SURFBOX = m_pOwner->getSurfaceBoxGlobal();
const auto LOCAL = SURFBOX.has_value() ? logicPositionHint() - SURFBOX->pos() : Vector2D{};
wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, m_pOwner->wlr(), LOCAL.x, LOCAL.y);
}
g_pCompositor->warpCursorTo(logicPositionHint(), true);
wlr_pointer_constraint_v1_send_activated(m_pConstraint);
}
bool CConstraint::active() {
return m_bActive;
}

View File

@@ -0,0 +1,44 @@
#pragma once
#include "../includes.hpp"
#include "../helpers/Region.hpp"
#include "../helpers/WLListener.hpp"
class CWLSurface;
class CConstraint {
public:
CConstraint(wlr_pointer_constraint_v1* constraint, CWLSurface* owner);
~CConstraint();
void onCommit();
void onDestroy();
void onSetRegion();
CRegion logicConstraintRegion();
bool isLocked();
Vector2D logicPositionHint();
void deactivate();
void activate();
bool active();
CWLSurface* owner();
private:
bool m_bActive = false;
CWLSurface* m_pOwner = nullptr;
wlr_pointer_constraint_v1* m_pConstraint;
CRegion m_rRegion;
bool m_bHintSet = false;
Vector2D m_vPositionHint = {-1, -1};
Vector2D m_vCursorPosOnActivate = {-1, -1};
// for oneshot constraints that have been activated once
bool m_bDead = false;
DYNLISTENER(destroyConstraint);
DYNLISTENER(setConstraintRegion);
void initSignals();
};

256
src/desktop/Popup.cpp Normal file
View File

@@ -0,0 +1,256 @@
#include "Popup.hpp"
#include "../Compositor.hpp"
CPopup::CPopup(CWindow* pOwner) : m_pWindowOwner(pOwner) {
initAllSignals();
}
CPopup::CPopup(SLayerSurface* pOwner) : m_pLayerOwner(pOwner) {
initAllSignals();
}
CPopup::CPopup(wlr_xdg_popup* popup, CPopup* pOwner) : m_pParent(pOwner), m_pWLR(popup) {
m_pWLR->base->data = this;
m_sWLSurface.assign(popup->base->surface, this);
m_pLayerOwner = pOwner->m_pLayerOwner;
m_pWindowOwner = pOwner->m_pWindowOwner;
m_vLastSize = {m_pWLR->current.geometry.width, m_pWLR->current.geometry.height};
unconstrain();
initAllSignals();
}
CPopup::~CPopup() {
m_sWLSurface.unassign();
if (m_pWLR)
m_pWLR->base->data = nullptr;
hyprListener_commitPopup.removeCallback();
hyprListener_repositionPopup.removeCallback();
hyprListener_mapPopup.removeCallback();
hyprListener_unmapPopup.removeCallback();
hyprListener_newPopup.removeCallback();
hyprListener_destroyPopup.removeCallback();
}
static void onNewPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onNewPopup((wlr_xdg_popup*)data);
}
static void onMapPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onMap();
}
static void onDestroyPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onDestroy();
}
static void onUnmapPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onUnmap();
}
static void onCommitPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onCommit();
}
static void onRepositionPopup(void* owner, void* data) {
const auto POPUP = (CPopup*)owner;
POPUP->onReposition();
}
void CPopup::initAllSignals() {
if (!m_pWLR) {
if (m_pWindowOwner)
hyprListener_newPopup.initCallback(&m_pWindowOwner->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head");
else if (m_pLayerOwner)
hyprListener_newPopup.initCallback(&m_pLayerOwner->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head");
else
ASSERT(false);
return;
}
hyprListener_repositionPopup.initCallback(&m_pWLR->events.reposition, ::onRepositionPopup, this, "CPopup");
hyprListener_destroyPopup.initCallback(&m_pWLR->events.destroy, ::onDestroyPopup, this, "CPopup");
hyprListener_mapPopup.initCallback(&m_sWLSurface.wlr()->events.map, ::onMapPopup, this, "CPopup");
hyprListener_unmapPopup.initCallback(&m_sWLSurface.wlr()->events.unmap, ::onUnmapPopup, this, "CPopup");
hyprListener_commitPopup.initCallback(&m_sWLSurface.wlr()->events.commit, ::onCommitPopup, this, "CPopup");
hyprListener_newPopup.initCallback(&m_pWLR->base->events.new_popup, ::onNewPopup, this, "CPopup");
}
void CPopup::onNewPopup(wlr_xdg_popup* popup) {
const auto POPUP = m_vChildren.emplace_back(std::make_unique<CPopup>(popup, this)).get();
Debug::log(LOG, "New popup at wlr {:x} and hl {:x}", (uintptr_t)popup, (uintptr_t)POPUP);
}
void CPopup::onDestroy() {
m_bInert = true;
if (!m_pParent)
return; // head node
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
}
void CPopup::onMap() {
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
const auto COORDS = coordsGlobal();
CBox box;
wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr());
box.applyFromWlr().translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(&box);
m_vLastPos = coordsRelativeToParent();
g_pInputManager->simulateMouseMovement();
m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
unconstrain();
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() {
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
const auto COORDS = coordsGlobal();
CBox box;
wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr());
box.applyFromWlr().translate(COORDS).expand(4);
g_pHyprRenderer->damageBox(&box);
m_pSubsurfaceHead.reset();
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) {
if (m_pWLR->base->initial_commit) {
wlr_xdg_surface_schedule_configure(m_pWLR->base);
return;
}
const auto COORDS = coordsGlobal();
const auto COORDSLOCAL = coordsRelativeToParent();
if (m_vLastSize != Vector2D{m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height} || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) {
CBox box = {localToGlobal(m_vLastPos), m_vLastSize};
g_pHyprRenderer->damageBox(&box);
m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height};
box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
m_vLastPos = COORDSLOCAL;
}
if (!ignoreSiblings)
m_pSubsurfaceHead->recheckDamageForSubsurfaces();
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
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() {
Debug::log(LOG, "Popup {:x} requests reposition", (uintptr_t)this);
m_bRequestedReposition = true;
m_vLastPos = coordsRelativeToParent();
unconstrain();
}
void CPopup::unconstrain() {
const auto COORDS = t1ParentCoords();
const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS);
if (!PMONITOR)
return;
CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(m_pWLR, box.pWlr());
}
Vector2D CPopup::coordsRelativeToParent() {
Vector2D offset;
CPopup* current = this;
offset -= {m_pWLR->base->current.geometry.x, m_pWLR->base->current.geometry.y};
while (current->m_pParent) {
offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy};
offset += {current->m_pWLR->current.geometry.x, current->m_pWLR->current.geometry.y};
current = current->m_pParent;
}
return offset;
}
Vector2D CPopup::coordsGlobal() {
return localToGlobal(coordsRelativeToParent());
}
Vector2D CPopup::localToGlobal(const Vector2D& rel) {
return t1ParentCoords() + rel;
}
Vector2D CPopup::t1ParentCoords() {
if (m_pWindowOwner)
return m_pWindowOwner->m_vRealPosition.value();
if (m_pLayerOwner)
return m_pLayerOwner->realPosition.value();
ASSERT(false);
return {};
}
void CPopup::recheckTree() {
CPopup* curr = this;
while (curr->m_pParent) {
curr = curr->m_pParent;
}
curr->recheckChildrenRecursive();
}
void CPopup::recheckChildrenRecursive() {
for (auto& c : m_vChildren) {
c->onCommit(true);
c->recheckChildrenRecursive();
}
}
Vector2D CPopup::size() {
return m_vLastSize;
}
void CPopup::sendScale() {
if (m_pWindowOwner)
g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pWindowOwner->m_pWLSurface.m_fLastScale);
else if (m_pLayerOwner)
g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pLayerOwner->surface.m_fLastScale);
else
UNREACHABLE();
}

72
src/desktop/Popup.hpp Normal file
View File

@@ -0,0 +1,72 @@
#pragma once
#include <vector>
#include <memory>
#include "Subsurface.hpp"
struct SLayerSurface;
class CPopup {
public:
// dummy head nodes
CPopup(CWindow* pOwner);
CPopup(SLayerSurface* pOwner);
// real nodes
CPopup(wlr_xdg_popup* popup, CPopup* pOwner);
~CPopup();
Vector2D coordsRelativeToParent();
Vector2D coordsGlobal();
Vector2D size();
void onNewPopup(wlr_xdg_popup* popup);
void onDestroy();
void onMap();
void onUnmap();
void onCommit(bool ignoreSiblings = false);
void onReposition();
void recheckTree();
CWLSurface m_sWLSurface;
private:
// T1 owners, each popup has to have one of these
CWindow* m_pWindowOwner = nullptr;
SLayerSurface* m_pLayerOwner = nullptr;
// T2 owners
CPopup* m_pParent = nullptr;
wlr_xdg_popup* m_pWLR = nullptr;
Vector2D m_vLastSize = {};
Vector2D m_vLastPos = {};
bool m_bRequestedReposition = false;
bool m_bInert = false;
//
std::vector<std::unique_ptr<CPopup>> m_vChildren;
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
// signals
DYNLISTENER(newPopup);
DYNLISTENER(destroyPopup);
DYNLISTENER(mapPopup);
DYNLISTENER(unmapPopup);
DYNLISTENER(commitPopup);
DYNLISTENER(repositionPopup);
void initAllSignals();
void unconstrain();
void recheckChildrenRecursive();
void sendScale();
Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords();
};

243
src/desktop/Subsurface.cpp Normal file
View File

@@ -0,0 +1,243 @@
#include "Subsurface.hpp"
#include "../events/Events.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
static void onNewSubsurface(void* owner, void* data);
CSubsurface::CSubsurface(CWindow* pOwner) : m_pWindowParent(pOwner) {
initSignals();
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) {
initSignals();
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) {
m_sWLSurface.assign(pSubsurface->surface, this);
initSignals();
initExistingSubsurfaces();
}
CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) {
m_sWLSurface.assign(pSubsurface->surface, this);
initSignals();
initExistingSubsurfaces();
}
CSubsurface::~CSubsurface() {
hyprListener_newSubsurface.removeCallback();
if (!m_pSubsurface)
return;
hyprListener_commitSubsurface.removeCallback();
hyprListener_destroySubsurface.removeCallback();
}
static void onNewSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onNewSubsurface((wlr_subsurface*)data);
}
static void onDestroySubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onDestroy();
}
static void onCommitSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onCommit();
}
static void onMapSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onMap();
}
static void onUnmapSubsurface(void* owner, void* data) {
const auto PSUBSURFACE = (CSubsurface*)owner;
PSUBSURFACE->onUnmap();
}
void CSubsurface::initSignals() {
if (m_pSubsurface) {
hyprListener_commitSubsurface.initCallback(&m_pSubsurface->surface->events.commit, &onCommitSubsurface, 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_mapSubsurface.initCallback(&m_pSubsurface->surface->events.map, &onMapSubsurface, this, "CSubsurface");
hyprListener_unmapSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface");
} else {
if (m_pWindowParent)
hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
else if (m_pPopupParent)
hyprListener_newSubsurface.initCallback(&m_pPopupParent->m_sWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head");
else
RASSERT(false, "CSubsurface::initSignals empty subsurface");
}
}
void CSubsurface::checkSiblingDamage() {
if (!m_pParent)
return; // ??????????
const double SCALE = m_pWindowParent && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0;
for (auto& n : m_pParent->m_vChildren) {
if (n.get() == this)
continue;
const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE);
}
}
void CSubsurface::recheckDamageForSubsurfaces() {
for (auto& n : m_vChildren) {
const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y);
}
}
void CSubsurface::onCommit() {
// no damaging if it's not visible
if (m_pWindowParent && !g_pHyprRenderer->shouldRenderWindow(m_pWindowParent)) {
m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.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_pWindowParent);
return;
}
const auto COORDS = coordsGlobal();
g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y);
if (m_pPopupParent)
m_pPopupParent->recheckTree();
if (m_pWindowParent) // I hate you firefox why are you doing this
m_pWindowParent->m_pPopupHead->recheckTree();
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
checkSiblingDamage();
if (m_vLastSize != Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}) {
CBox box{COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
box = {COORDS, m_vLastSize};
g_pHyprRenderer->damageBox(&box);
}
}
void CSubsurface::onDestroy() {
// destroy children
m_vChildren.clear();
m_bInert = true;
if (!m_pSubsurface)
return; // dummy node, nothing to do, it's the parent dying
// kill ourselves
std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; });
}
void CSubsurface::onNewSubsurface(wlr_subsurface* pSubsurface) {
CSubsurface* PSUBSURFACE = nullptr;
if (m_pWindowParent)
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pWindowParent)).get();
else if (m_pPopupParent)
PSUBSURFACE = m_vChildren.emplace_back(std::make_unique<CSubsurface>(pSubsurface, m_pPopupParent)).get();
PSUBSURFACE->m_pParent = this;
ASSERT(PSUBSURFACE);
}
void CSubsurface::onMap() {
m_vLastSize = {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize};
box.expand(4);
g_pHyprRenderer->damageBox(&box);
if (m_pWindowParent)
m_pWindowParent->updateSurfaceScaleTransformDetails();
}
void CSubsurface::onUnmap() {
const auto COORDS = coordsGlobal();
CBox box{COORDS, m_vLastSize};
box.expand(4);
g_pHyprRenderer->damageBox(&box);
if (m_sWLSurface.wlr() == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons();
g_pInputManager->simulateMouseMovement();
// TODO: should this remove children? Currently it won't, only on .destroy
}
Vector2D CSubsurface::coordsRelativeToParent() {
Vector2D offset;
CSubsurface* current = this;
while (current->m_pParent) {
offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy};
offset += {current->m_pSubsurface->current.x, current->m_pSubsurface->current.y};
current = current->m_pParent;
}
return offset;
}
Vector2D CSubsurface::coordsGlobal() {
Vector2D coords = coordsRelativeToParent();
if (m_pWindowParent)
coords += m_pWindowParent->m_vRealPosition.value();
else if (m_pPopupParent)
coords += m_pPopupParent->coordsGlobal();
return coords;
}
void CSubsurface::initExistingSubsurfaces() {
if (m_pWindowParent)
return;
wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_below, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
wl_list_for_each(wlrSubsurface, &m_sWLSurface.wlr()->current.subsurfaces_above, current.link) {
::onNewSubsurface(this, wlrSubsurface);
}
}
Vector2D CSubsurface::size() {
return {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height};
}

View File

@@ -0,0 +1,59 @@
#pragma once
#include "../defines.hpp"
#include <vector>
#include "WLSurface.hpp"
class CWindow;
class CPopup;
class CSubsurface {
public:
// root dummy nodes
CSubsurface(CWindow* pOwner);
CSubsurface(CPopup* pOwner);
// real nodes
CSubsurface(wlr_subsurface* pSubsurface, CWindow* pOwner);
CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner);
~CSubsurface();
Vector2D coordsRelativeToParent();
Vector2D coordsGlobal();
Vector2D size();
void onCommit();
void onDestroy();
void onNewSubsurface(wlr_subsurface* pSubsurface);
void onMap();
void onUnmap();
void recheckDamageForSubsurfaces();
private:
DYNLISTENER(destroySubsurface);
DYNLISTENER(commitSubsurface);
DYNLISTENER(newSubsurface);
DYNLISTENER(mapSubsurface);
DYNLISTENER(unmapSubsurface);
wlr_subsurface* m_pSubsurface = nullptr;
CWLSurface m_sWLSurface;
Vector2D m_vLastSize = {};
// if nullptr, means it's a dummy node
CSubsurface* m_pParent = nullptr;
CWindow* m_pWindowParent = nullptr;
CPopup* m_pPopupParent = nullptr;
std::vector<std::unique_ptr<CSubsurface>> m_vChildren;
bool m_bInert = false;
void initSignals();
void initExistingSubsurfaces();
void checkSiblingDamage();
};

196
src/desktop/WLSurface.cpp Normal file
View File

@@ -0,0 +1,196 @@
#include "WLSurface.hpp"
#include "../Compositor.hpp"
void CWLSurface::assign(wlr_surface* pSurface) {
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, CWindow* pOwner) {
m_pWindowOwner = pOwner;
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, SLayerSurface* pOwner) {
m_pLayerOwner = pOwner;
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, CSubsurface* pOwner) {
m_pSubsurfaceOwner = pOwner;
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::assign(wlr_surface* pSurface, CPopup* pOwner) {
m_pPopupOwner = pOwner;
m_pWLRSurface = pSurface;
init();
m_bInert = false;
}
void CWLSurface::unassign() {
destroy();
}
CWLSurface::~CWLSurface() {
destroy();
}
bool CWLSurface::exists() const {
return m_pWLRSurface;
}
wlr_surface* CWLSurface::wlr() const {
return m_pWLRSurface;
}
bool CWLSurface::small() const {
if (!m_pWindowOwner || !exists())
return false;
return m_pWindowOwner->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || m_pWindowOwner->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1;
}
Vector2D CWLSurface::correctSmallVec() const {
if (!m_pWindowOwner || !exists() || !small() || m_bFillIgnoreSmall)
return {};
const auto SIZE = getViewporterCorrectedSize();
return Vector2D{(m_pWindowOwner->m_vReportedSize.x - SIZE.x) / 2, (m_pWindowOwner->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) *
(m_pWindowOwner->m_vRealSize.value() / m_pWindowOwner->m_vReportedSize);
}
Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists())
return {};
return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} :
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
}
CRegion CWLSurface::logicalDamage() const {
CRegion damage{&m_pWLRSurface->buffer_damage};
damage.transform(m_pWLRSurface->current.transform, m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height);
damage.scale(1.0 / m_pWLRSurface->current.scale);
const auto VPSIZE = getViewporterCorrectedSize();
const auto CORRECTVEC = correctSmallVec();
if (m_pWLRSurface->current.viewport.has_src) {
damage.intersect(CBox{std::floor(m_pWLRSurface->current.viewport.src.x), std::floor(m_pWLRSurface->current.viewport.src.y),
std::ceil(m_pWLRSurface->current.viewport.src.width), std::ceil(m_pWLRSurface->current.viewport.src.height)});
}
const auto SCALEDSRCSIZE = m_pWLRSurface->current.viewport.has_src ?
Vector2D{m_pWLRSurface->current.viewport.src.width, m_pWLRSurface->current.viewport.src.height} * m_pWLRSurface->current.scale :
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y});
damage.translate(CORRECTVEC);
return damage;
}
void CWLSurface::destroy() {
if (!m_pWLRSurface)
return;
m_pConstraint.reset();
hyprListener_destroy.removeCallback();
hyprListener_commit.removeCallback();
m_pWLRSurface->data = nullptr;
m_pWindowOwner = nullptr;
m_pLayerOwner = nullptr;
m_pPopupOwner = nullptr;
m_pSubsurfaceOwner = nullptr;
m_bInert = true;
if (g_pCompositor && g_pCompositor->m_pLastFocus == m_pWLRSurface)
g_pCompositor->m_pLastFocus = nullptr;
if (g_pInputManager && g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_pWLRSurface = nullptr;
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
}
static void onCommit(void* owner, void* data) {
const auto SURF = (CWLSurface*)owner;
SURF->onCommit();
}
void CWLSurface::init() {
if (!m_pWLRSurface)
return;
RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!");
m_pWLRSurface->data = this;
hyprListener_destroy.initCallback(
&m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
hyprListener_commit.initCallback(&m_pWLRSurface->events.commit, ::onCommit, this, "CWLSurface");
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
}
CWindow* CWLSurface::getWindow() {
return m_pWindowOwner;
}
SLayerSurface* CWLSurface::getLayer() {
return m_pLayerOwner;
}
CPopup* CWLSurface::getPopup() {
return m_pPopupOwner;
}
CSubsurface* CWLSurface::getSubsurface() {
return m_pSubsurfaceOwner;
}
bool CWLSurface::desktopComponent() {
return m_pLayerOwner || m_pWindowOwner || m_pSubsurfaceOwner || m_pPopupOwner;
}
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() {
if (!desktopComponent())
return {};
if (m_pWindowOwner)
return m_pWindowOwner->getWindowMainSurfaceBox();
if (m_pLayerOwner)
return m_pLayerOwner->geometry;
if (m_pPopupOwner)
return CBox{m_pPopupOwner->coordsGlobal(), m_pPopupOwner->size()};
if (m_pSubsurfaceOwner)
return CBox{m_pSubsurfaceOwner->coordsGlobal(), m_pSubsurfaceOwner->size()};
return {};
}
void CWLSurface::appendConstraint(wlr_pointer_constraint_v1* constraint) {
m_pConstraint = std::make_unique<CConstraint>(constraint, this);
}
void CWLSurface::onCommit() {
if (m_pConstraint)
m_pConstraint->onCommit();
}
CConstraint* CWLSurface::constraint() {
return m_pConstraint.get();
}

View File

@@ -1,16 +1,25 @@
#pragma once
#include "../defines.hpp"
#include "../helpers/Region.hpp"
#include "Constraint.hpp"
class CWindow;
struct SLayerSurface;
class CSubsurface;
class CPopup;
class CWLSurface {
public:
CWLSurface() = default;
CWLSurface(wlr_surface* pSurface);
~CWLSurface();
// anonymous surfaces are non-desktop components, e.g. a cursor surface or a DnD
void assign(wlr_surface* pSurface);
void assign(wlr_surface* pSurface, CWindow* pOwner);
void assign(wlr_surface* pSurface, SLayerSurface* pOwner);
void assign(wlr_surface* pSurface, CSubsurface* pOwner);
void assign(wlr_surface* pSurface, CPopup* pOwner);
void unassign();
CWLSurface(const CWLSurface&) = delete;
@@ -23,13 +32,23 @@ class CWLSurface {
bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D getViewporterCorrectedSize() const;
CRegion logicalDamage() const;
void onCommit();
// getters for owners.
CWindow* getWindow();
SLayerSurface* getLayer();
CPopup* getPopup();
CSubsurface* getSubsurface();
// desktop components misc utils
std::optional<CBox> getSurfaceBoxGlobal();
void appendConstraint(wlr_pointer_constraint_v1* constraint);
CConstraint* constraint();
// allow stretching. Useful for plugins.
bool m_bFillIgnoreSmall = false;
// if present, means this is a base surface of a window. Cleaned on unassign()
CWindow* m_pOwner = nullptr;
// track surface data and avoid dupes
float m_fLastScale = 0;
int m_iLastScale = 0;
@@ -57,14 +76,30 @@ class CWLSurface {
}
static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) {
if (!pSurface)
return nullptr;
return (CWLSurface*)pSurface->data;
}
private:
bool m_bInert = true;
wlr_surface* m_pWLRSurface = nullptr;
CWindow* m_pWindowOwner = nullptr;
SLayerSurface* m_pLayerOwner = nullptr;
CPopup* m_pPopupOwner = nullptr;
CSubsurface* m_pSubsurfaceOwner = nullptr;
//
std::unique_ptr<CConstraint> m_pConstraint;
void destroy();
void init();
bool desktopComponent();
DYNLISTENER(destroy);
DYNLISTENER(commit);
friend class CConstraint;
};

View File

@@ -1,18 +1,19 @@
#include "Window.hpp"
#include "Compositor.hpp"
#include "render/decorations/CHyprDropShadowDecoration.hpp"
#include "render/decorations/CHyprGroupBarDecoration.hpp"
#include "render/decorations/CHyprBorderDecoration.hpp"
#include "../Compositor.hpp"
#include "../render/decorations/CHyprDropShadowDecoration.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../render/decorations/CHyprBorderDecoration.hpp"
#include "../config/ConfigValue.hpp"
CWindow::CWindow() {
m_vRealPosition.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_vRealSize.create(AVARTYPE_VECTOR, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_fBorderFadeAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("border"), (void*)this, AVARDAMAGE_BORDER);
m_fBorderAngleAnimationProgress.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("borderangle"), (void*)this, AVARDAMAGE_BORDER);
m_fAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), (void*)this, AVARDAMAGE_ENTIRE);
m_fActiveInactiveAlpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), (void*)this, AVARDAMAGE_ENTIRE);
m_cRealShadowColor.create(AVARTYPE_COLOR, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), (void*)this, AVARDAMAGE_SHADOW);
m_fDimPercent.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), (void*)this, AVARDAMAGE_ENTIRE);
m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), this, AVARDAMAGE_ENTIRE);
m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), this, AVARDAMAGE_ENTIRE);
m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), this, AVARDAMAGE_BORDER);
m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), this, AVARDAMAGE_BORDER);
m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), this, AVARDAMAGE_ENTIRE);
m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), this, AVARDAMAGE_ENTIRE);
m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), this, AVARDAMAGE_SHADOW);
m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), this, AVARDAMAGE_ENTIRE);
addWindowDeco(std::make_unique<CHyprDropShadowDecoration>(this));
addWindowDeco(std::make_unique<CHyprBorderDecoration>(this));
@@ -39,8 +40,8 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() {
if (m_sAdditionalConfigData.dimAround) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
return {{m_vRealPosition.vec().x - PMONITOR->vecPosition.x, m_vRealPosition.vec().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition.vec().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.vec().y - PMONITOR->vecPosition.y)}};
return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y},
{PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}};
}
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
@@ -101,8 +102,8 @@ CBox CWindow::getFullWindowBoundingBox() {
auto maxExtents = getFullWindowExtents();
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
CBox finalBox = {m_vRealPosition.value().x - maxExtents.topLeft.x, m_vRealPosition.value().y - maxExtents.topLeft.y,
m_vRealSize.value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox;
}
@@ -154,14 +155,14 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) {
if (properties & FULL_EXTENTS)
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, false));
CBox box = {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
CBox box = {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
box.addExtents(EXTENTS);
return box;
}
CBox CWindow::getWindowMainSurfaceBox() {
return {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y};
}
SWindowDecorationExtents CWindow::getFullWindowReservedArea() {
@@ -193,7 +194,14 @@ void CWindow::updateWindowDecos() {
m_vDecosToRemove.clear();
// make a copy because updateWindow can remove decos.
std::vector<IHyprWindowDecoration*> decos;
for (auto& wd : m_dWindowDecorations) {
decos.push_back(wd.get());
}
for (auto& wd : decos) {
wd->updateWindow(this);
}
}
@@ -239,13 +247,12 @@ bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoor
pid_t CWindow::getPID() {
pid_t PID = -1;
if (!m_bIsX11) {
if (!m_bIsMapped)
if (!m_uSurface.xdg)
return -1;
wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr);
} else {
if (!m_bIsMapped)
if (!m_uSurface.xwayland)
return -1;
PID = m_uSurface.xwayland->pid;
@@ -336,7 +343,7 @@ void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
}
void CWindow::updateSurfaceScaleTransformDetails() {
if (!m_bIsMapped || m_bHidden)
if (!m_bIsMapped || m_bHidden || g_pCompositor->m_bUnsafeState)
return;
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
@@ -345,6 +352,9 @@ void CWindow::updateSurfaceScaleTransformDetails() {
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
if (!PNEWMONITOR)
return;
if (PNEWMONITOR != PLASTMONITOR) {
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
@@ -371,7 +381,7 @@ void CWindow::moveToWorkspace(int workspaceID) {
if (m_iWorkspaceID == workspaceID)
return;
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
const int OLDWORKSPACE = m_iWorkspaceID;
@@ -379,10 +389,13 @@ void CWindow::moveToWorkspace(int workspaceID) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
setAnimationsToMove();
updateSpecialRenderData();
if (PWORKSPACE) {
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)});
EMIT_HOOK_EVENT("moveWindow", (std::vector<void*>{this, PWORKSPACE}));
}
@@ -392,7 +405,7 @@ void CWindow::moveToWorkspace(int workspaceID) {
}
// update xwayland coords
g_pXWaylandManager->setWindowSize(this, m_vRealSize.vec());
g_pXWaylandManager->setWindowSize(this, m_vRealSize.value());
if (g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE) == 0 && *PCLOSEONLASTSPECIAL) {
const auto PWS = g_pCompositor->getWorkspaceByID(OLDWORKSPACE);
@@ -433,11 +446,11 @@ void CWindow::removeDecorationByType(eDecorationType type) {
}
void unregisterVar(void* ptr) {
((CAnimatedVariable*)ptr)->unregister();
((CBaseAnimatedVariable*)ptr)->unregister();
}
void CWindow::onUnmap() {
static auto* const PCLOSEONLASTSPECIAL = &g_pConfigManager->getConfigValuePtr("misc:close_special_on_empty")->intValue;
static auto PCLOSEONLASTSPECIAL = CConfigValue<Hyprlang::INT>("misc:close_special_on_empty");
if (g_pCompositor->m_pLastWindow == this)
g_pCompositor->m_pLastWindow = nullptr;
@@ -455,8 +468,6 @@ void CWindow::onUnmap() {
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other == this; });
m_pWLSurface.unassign();
hyprListener_unmapWindow.removeCallback();
if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(m_iWorkspaceID) == 0 && g_pCompositor->isWorkspaceSpecial(m_iWorkspaceID)) {
@@ -471,13 +482,15 @@ void CWindow::onUnmap() {
PMONITOR->solitaryClient = nullptr;
g_pCompositor->updateWorkspaceWindows(m_iWorkspaceID);
if (m_bIsX11)
return;
m_pSubsurfaceHead.reset();
m_pPopupHead.reset();
}
void CWindow::onMap() {
m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(this));
m_pWLSurface.m_pOwner = 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)
m_vRealPosition.resetAllCallbacks();
m_vRealSize.resetAllCallbacks();
@@ -508,6 +521,7 @@ void CWindow::onMap() {
"CWindow");
m_vReportedSize = m_vPendingReportedSize;
m_bAnimatingIn = true;
for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) {
if (ctrl->pWlrHint->surface != m_pWLSurface.wlr())
@@ -516,10 +530,16 @@ void CWindow::onMap() {
m_bTearingHint = ctrl->pWlrHint->current;
break;
}
if (m_bIsX11)
return;
m_pSubsurfaceHead = std::make_unique<CSubsurface>(this);
m_pPopupHead = std::make_unique<CPopup>(this);
}
void CWindow::onBorderAngleAnimEnd(void* ptr) {
const auto PANIMVAR = (CAnimatedVariable*)ptr;
const auto PANIMVAR = (CAnimatedVariable<float>*)ptr;
const std::string STYLE = PANIMVAR->getConfig()->pValues->internalStyle;
@@ -673,6 +693,38 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
m_eIdleInhibitMode = IDLEINHIBIT_FULLSCREEN;
else
Debug::log(ERR, "Rule idleinhibit: unknown mode {}", IDLERULE);
} else if (r.szRule.starts_with("maxsize")) {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r.szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for maxsize");
return;
}
m_sAdditionalConfigData.maxSize = VEC;
m_vRealSize = Vector2D(std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().x, m_vRealSize.goal().x),
std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(this, m_vRealSize.goal());
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
} else if (r.szRule.starts_with("minsize")) {
try {
if (!m_bIsFloating)
return;
const auto VEC = configStringToVector2D(r.szRule.substr(8));
if (VEC.x < 1 || VEC.y < 1) {
Debug::log(ERR, "Invalid size for minsize");
return;
}
m_sAdditionalConfigData.minSize = VEC;
m_vRealSize = Vector2D(std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().x, m_vRealSize.goal().x),
std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().y, m_vRealSize.goal().y));
g_pXWaylandManager->setWindowSize(this, m_vRealSize.goal());
setHidden(false);
} catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); }
}
}
@@ -687,6 +739,8 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.forceNoDim = false;
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = false;
m_sAdditionalConfigData.maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
m_sAdditionalConfigData.minSize = Vector2D(20, 20);
m_sAdditionalConfigData.forceNoAnims = false;
m_sAdditionalConfigData.animationStyle = std::string("");
m_sAdditionalConfigData.rounding = -1;
@@ -716,10 +770,10 @@ bool CWindow::isInCurvedCorner(double x, double y) {
return false;
// (x0, y0), (x0, y1), ... are the center point of rounding at each corner
double x0 = m_vRealPosition.vec().x + ROUNDING;
double y0 = m_vRealPosition.vec().y + ROUNDING;
double x1 = m_vRealPosition.vec().x + m_vRealSize.vec().x - ROUNDING;
double y1 = m_vRealPosition.vec().y + m_vRealSize.vec().y - ROUNDING;
double x0 = m_vRealPosition.value().x + ROUNDING;
double y0 = m_vRealPosition.value().y + ROUNDING;
double x1 = m_vRealPosition.value().x + m_vRealSize.value().x - ROUNDING;
double y1 = m_vRealPosition.value().y + m_vRealSize.value().y - ROUNDING;
if (x < x0 && y < y0) {
return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING;
@@ -752,7 +806,7 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
return false;
wlr_surface* resultSurf = nullptr;
Vector2D origin = m_vRealPosition.vec();
Vector2D origin = m_vRealPosition.value();
SExtensionFindingData data = {origin, pos, &resultSurf};
wlr_xdg_surface_for_each_popup_surface(m_uSurface.xdg, findExtensionForVector2D, &data);
@@ -891,8 +945,8 @@ void CWindow::setGroupCurrent(CWindow* pWindow) {
const bool FULLSCREEN = PCURRENT->m_bIsFullscreen;
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PCURRENT->m_iWorkspaceID);
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goalv();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goalv();
const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal();
const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal();
const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow;
@@ -986,19 +1040,22 @@ void CWindow::updateGroupOutputs() {
curr->m_iMonitorID = m_iMonitorID;
curr->moveToWorkspace(m_iWorkspaceID);
curr->m_vRealPosition = m_vRealPosition.goalv();
curr->m_vRealSize = m_vRealSize.goalv();
curr->m_vRealPosition = m_vRealPosition.goal();
curr->m_vRealSize = m_vRealSize.goal();
curr = curr->m_sGroupData.pNextWindow;
}
}
Vector2D CWindow::middle() {
return m_vRealPosition.goalv() + m_vRealSize.goalv() / 2.f;
return m_vRealPosition.goal() + m_vRealSize.goal() / 2.f;
}
bool CWindow::opaque() {
if (m_fAlpha.fl() != 1.f || m_fActiveInactiveAlpha.fl() != 1.f)
if (m_fAlpha.value() != 1.f || m_fActiveInactiveAlpha.value() != 1.f)
return false;
if (m_vRealSize.goal().floor() != m_vReportedSize)
return false;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
@@ -1006,7 +1063,7 @@ bool CWindow::opaque() {
if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall)
return false;
if (PWORKSPACE->m_fAlpha.fl() != 1.f)
if (PWORKSPACE->m_fAlpha.value() != 1.f)
return false;
if (m_bIsX11)
@@ -1023,7 +1080,7 @@ bool CWindow::opaque() {
}
float CWindow::rounding() {
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
static auto PROUNDING = CConfigValue<Hyprlang::INT>("decoration:rounding");
float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying();
@@ -1032,17 +1089,32 @@ float CWindow::rounding() {
void CWindow::updateSpecialRenderData() {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{};
const auto WORKSPACERULES = PWORKSPACE ? g_pConfigManager->getWorkspaceRulesFor(PWORKSPACE) : std::vector<SWorkspaceRule>{};
bool border = true;
if (m_bIsFloating && g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue == 1)
static auto PNOBORDERONFLOATING = CConfigValue<Hyprlang::INT>("general:no_border_on_floating");
if (m_bIsFloating && *PNOBORDERONFLOATING == 1)
border = false;
m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(border);
m_sSpecialRenderData.borderSize = WORKSPACERULE.borderSize.value_or(-1);
m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true);
m_sSpecialRenderData.rounding = WORKSPACERULE.rounding.value_or(true);
m_sSpecialRenderData.shadow = WORKSPACERULE.shadow.value_or(true);
m_sSpecialRenderData.border = border;
m_sSpecialRenderData.borderSize = -1;
m_sSpecialRenderData.decorate = true;
m_sSpecialRenderData.rounding = true;
m_sSpecialRenderData.shadow = true;
for (auto& wsRule : WORKSPACERULES) {
if (wsRule.border.has_value())
m_sSpecialRenderData.border = wsRule.border.value();
if (wsRule.borderSize.has_value())
m_sSpecialRenderData.borderSize = wsRule.borderSize.value();
if (wsRule.decorate.has_value())
m_sSpecialRenderData.decorate = wsRule.decorate.value();
if (wsRule.rounding.has_value())
m_sSpecialRenderData.rounding = wsRule.rounding.value();
if (wsRule.shadow.has_value())
m_sSpecialRenderData.shadow = wsRule.shadow.value();
}
}
int CWindow::getRealBorderSize() {
@@ -1055,7 +1127,9 @@ int CWindow::getRealBorderSize() {
if (m_sSpecialRenderData.borderSize.toUnderlying() != -1)
return m_sSpecialRenderData.borderSize.toUnderlying();
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
static auto PBORDERSIZE = CConfigValue<Hyprlang::INT>("general:border_size");
return *PBORDERSIZE;
}
bool CWindow::canBeTorn() {
@@ -1064,7 +1138,7 @@ bool CWindow::canBeTorn() {
bool CWindow::shouldSendFullscreenState() {
const auto MODE = g_pCompositor->getWorkspaceByID(m_iWorkspaceID)->m_efFullscreenMode;
return m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL));
return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL)));
}
void CWindow::setSuspended(bool suspend) {
@@ -1077,3 +1151,64 @@ void CWindow::setSuspended(bool suspend) {
wlr_xdg_toplevel_set_suspended(m_uSurface.xdg->toplevel, suspend);
m_bSuspended = suspend;
}
bool CWindow::visibleOnMonitor(CMonitor* pMonitor) {
CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()};
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 = g_pCompositor->getWorkspaceByID(m_iWorkspaceID);
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;
}

View File

@@ -1,15 +1,16 @@
#pragma once
#include "defines.hpp"
#include "helpers/SubsurfaceTree.hpp"
#include "helpers/AnimatedVariable.hpp"
#include "render/decorations/IHyprWindowDecoration.hpp"
#include "../defines.hpp"
#include "Subsurface.hpp"
#include "../helpers/AnimatedVariable.hpp"
#include "../render/decorations/IHyprWindowDecoration.hpp"
#include <deque>
#include "config/ConfigDataValues.hpp"
#include "helpers/Vector2D.hpp"
#include "helpers/WLSurface.hpp"
#include "macros.hpp"
#include "managers/XWaylandManager.hpp"
#include "../config/ConfigDataValues.hpp"
#include "../helpers/Vector2D.hpp"
#include "WLSurface.hpp"
#include "Popup.hpp"
#include "../macros.hpp"
#include "../managers/XWaylandManager.hpp"
enum eIdleInhibitMode {
IDLEINHIBIT_NONE = 0,
@@ -37,7 +38,15 @@ enum eGetWindowProperties {
FULL_EXTENTS = 1 << 2,
FLOATING_ONLY = 1 << 3,
ALLOW_FLOATING = 1 << 4,
USE_PROP_TILED = 1 << 5
USE_PROP_TILED = 1 << 5,
};
enum eSuppressEvents {
SUPPRESS_NONE = 0,
SUPPRESS_FULLSCREEN = 1 << 0,
SUPPRESS_MAXIMIZE = 1 << 1,
SUPPRESS_ACTIVATE = 1 << 2,
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
};
class IWindowTransformer;
@@ -143,8 +152,11 @@ struct SWindowAdditionalConfigData {
CWindowOverridableVar<bool> forceNoBorder = false;
CWindowOverridableVar<bool> forceNoShadow = false;
CWindowOverridableVar<bool> forceNoDim = false;
CWindowOverridableVar<bool> noFocus = false;
CWindowOverridableVar<bool> windowDanceCompat = false;
CWindowOverridableVar<bool> noMaxSize = false;
CWindowOverridableVar<Vector2D> maxSize = Vector2D(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
CWindowOverridableVar<Vector2D> minSize = Vector2D(20, 20);
CWindowOverridableVar<bool> dimAround = false;
CWindowOverridableVar<bool> forceRGBX = false;
CWindowOverridableVar<bool> keepAspectRatio = false;
@@ -168,7 +180,7 @@ struct SWindowRule {
int bFullscreen = -1;
int bPinned = -1;
int bFocus = -1;
int iOnWorkspace = -1;
std::string szOnWorkspace = ""; // empty means any
std::string szWorkspace = ""; // empty means any
};
@@ -184,7 +196,6 @@ class CWindow {
DYNLISTENER(setTitleWindow);
DYNLISTENER(setGeometryX11U);
DYNLISTENER(fullscreenWindow);
DYNLISTENER(newPopupXDG);
DYNLISTENER(requestMove);
DYNLISTENER(requestMinimize);
DYNLISTENER(requestMaximize);
@@ -201,7 +212,6 @@ class CWindow {
// DYNLISTENER(newSubsurfaceWindow);
CWLSurface m_pWLSurface;
std::list<CWLSurface> m_lPopupSurfaces;
union {
wlr_xdg_surface* xdg;
@@ -213,8 +223,8 @@ class CWindow {
Vector2D m_vSize = Vector2D(0, 0);
// this is the real position and size used to draw the thing
CAnimatedVariable m_vRealPosition;
CAnimatedVariable m_vRealSize;
CAnimatedVariable<Vector2D> m_vRealPosition;
CAnimatedVariable<Vector2D> m_vRealSize;
// for not spamming the protocols
Vector2D m_vReportedPosition;
@@ -227,6 +237,9 @@ class CWindow {
Vector2D m_vLastFloatingSize;
Vector2D m_vLastFloatingPosition;
// for floating window offset in workspace animations
Vector2D m_vFloatingOffset = Vector2D(0, 0);
// this is used for pseudotiling
bool m_bIsPseudotiled = false;
Vector2D m_vPseudoSize = Vector2D(0, 0);
@@ -235,6 +248,7 @@ class CWindow {
bool m_bIsFloating = false;
bool m_bDraggingTiled = false; // for dragging around tiled windows
bool m_bIsFullscreen = false;
bool m_bDontSendFullscreen = false;
bool m_bWasMaximized = false;
uint64_t m_iMonitorID = -1;
std::string m_szTitle = "";
@@ -260,29 +274,32 @@ class CWindow {
//
// For nofocus
bool m_bNoFocus = false;
bool m_bNoInitialFocus = false;
// Fullscreen and Maximize
bool m_bWantsInitialFullscreen = false;
bool m_bNoFullscreenRequest = false;
bool m_bNoMaximizeRequest = false;
SSurfaceTreeNode* m_pSurfaceTree = nullptr;
// bitfield eSuppressEvents
uint64_t m_eSuppressedEvents = SUPPRESS_NONE;
// desktop components
std::unique_ptr<CSubsurface> m_pSubsurfaceHead;
std::unique_ptr<CPopup> m_pPopupHead;
// Animated border
CGradientValueData m_cRealBorderColor = {0};
CGradientValueData m_cRealBorderColorPrevious = {0};
CAnimatedVariable m_fBorderFadeAnimationProgress;
CAnimatedVariable m_fBorderAngleAnimationProgress;
CAnimatedVariable<float> m_fBorderFadeAnimationProgress;
CAnimatedVariable<float> m_fBorderAngleAnimationProgress;
// Fade in-out
CAnimatedVariable m_fAlpha;
CAnimatedVariable<float> m_fAlpha;
bool m_bFadingOut = false;
bool m_bReadyToDelete = false;
Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in
Vector2D m_vOriginalClosedSize; // drawing the closing animations
SWindowDecorationExtents m_eOriginalClosedExtents;
bool m_bAnimatingIn = false;
// For pinned (sticky) windows
bool m_bPinned = false;
@@ -311,13 +328,13 @@ class CWindow {
std::vector<std::unique_ptr<IWindowTransformer>> m_vTransformers;
// for alpha
CAnimatedVariable m_fActiveInactiveAlpha;
CAnimatedVariable<float> m_fActiveInactiveAlpha;
// animated shadow color
CAnimatedVariable m_cRealShadowColor;
CAnimatedVariable<CColor> m_cRealShadowColor;
// animated tint
CAnimatedVariable m_fDimPercent;
CAnimatedVariable<float> m_fDimPercent;
// swallowing
CWindow* m_pSwallowed = nullptr;
@@ -382,6 +399,7 @@ class CWindow {
bool canBeTorn();
bool shouldSendFullscreenState();
void setSuspended(bool suspend);
bool visibleOnMonitor(CMonitor* pMonitor);
int getRealBorderSize();
void updateSpecialRenderData();
@@ -389,6 +407,7 @@ class CWindow {
void onBorderAngleAnimEnd(void* ptr);
bool isInCurvedCorner(double x, double y);
bool hasPopupAt(const Vector2D& pos);
int popupsCount();
void applyGroupRules();
void createGroup();
@@ -404,6 +423,8 @@ class CWindow {
void insertWindowToGroup(CWindow* pWindow);
void updateGroupOutputs();
void switchWithWindowInGroup(CWindow* pWindow);
void setAnimationsToMove();
void onWorkspaceAnimUpdate();
private:
// For hidden windows and stuff

398
src/desktop/Workspace.cpp Normal file
View File

@@ -0,0 +1,398 @@
#include "Workspace.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) {
Debug::log(ERR, "Attempted a creation of CWorkspace with an invalid monitor?");
return;
}
m_iMonitorID = monitorID;
m_iID = id;
m_szName = name;
m_bIsSpecialWorkspace = special;
m_vRenderOffset.create(special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), this,
AVARDAMAGE_ENTIRE);
m_fAlpha.create(AVARTYPE_FLOAT, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), this,
AVARDAMAGE_ENTIRE);
m_fAlpha.setValueAndWarp(1.f);
m_vRenderOffset.registerVar();
m_fAlpha.registerVar();
const auto RULESFORTHIS = g_pConfigManager->getWorkspaceRulesFor(this);
for (auto& rule : RULESFORTHIS) {
if (rule.defaultName.has_value())
m_szName = rule.defaultName.value();
}
g_pEventManager->postEvent({"createworkspace", m_szName});
g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)});
EMIT_HOOK_EVENT("createWorkspace", this);
}
CWorkspace::~CWorkspace() {
m_vRenderOffset.unregister();
Debug::log(LOG, "Destroying workspace ID {}", m_iID);
g_pEventManager->postEvent({"destroyworkspace", m_szName});
g_pEventManager->postEvent({"destroyworkspacev2", std::format("{},{}", m_iID, m_szName)});
EMIT_HOOK_EVENT("destroyWorkspace", this);
}
void CWorkspace::startAnim(bool in, bool left, bool instant) {
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces");
// set floating windows offset callbacks
m_vRenderOffset.setUpdateCallback([&](void*) {
for (auto& w : g_pCompositor->m_vWindows) {
if (!g_pCompositor->windowValidMapped(w.get()) || w->m_iWorkspaceID != m_iID)
continue;
w->onWorkspaceAnimUpdate();
};
});
if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
float movePerc = 100.f;
if (ANIMSTYLE.find("%") != std::string::npos) {
try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1);
movePerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); }
}
m_fAlpha.setValueAndWarp(1.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0);
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
m_vRenderOffset = Vector2D(0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
}
} else {
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0));
m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0);
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0);
}
}
} else if (ANIMSTYLE == "fade") {
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade.
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_fAlpha = 1.f;
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
}
} else if (ANIMSTYLE == "slidevert") {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? YDISTANCE : -YDISTANCE));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(0, left ? -YDISTANCE : YDISTANCE);
}
} else {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0);
}
}
if (m_bIsSpecialWorkspace) {
// required for open/close animations
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_fAlpha = 1.f;
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
}
}
if (instant) {
m_vRenderOffset.warp();
m_fAlpha.warp();
}
}
void CWorkspace::setActive(bool on) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
void CWorkspace::moveToMonitor(const int& id) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
CWindow* CWorkspace::getLastFocusedWindow() {
if (!g_pCompositor->windowValidMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow->m_iWorkspaceID != m_iID)
return nullptr;
return m_pLastFocusedWindow;
}
void CWorkspace::rememberPrevWorkspace(const CWorkspace* prev) {
if (!prev) {
m_sPrevWorkspace.iID = -1;
m_sPrevWorkspace.name = "";
return;
}
if (prev->m_iID == m_iID) {
Debug::log(LOG, "Tried to set prev workspace to the same as current one");
return;
}
m_sPrevWorkspace.iID = prev->m_iID;
m_sPrevWorkspace.name = prev->m_szName;
}
std::string CWorkspace::getConfigName() {
if (m_bIsSpecialWorkspace) {
return "special:" + m_szName;
}
if (m_iID > 0)
return std::to_string(m_iID);
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[0-4] or w[1], optional flag t or f for tiled or floating, e.g. w[t0-1]
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:"))
return m_szName.starts_with(prop.substr(2));
if (prop.starts_with("e:"))
return m_szName.ends_with(prop.substr(2));
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;
if (prop.starts_with("t")) {
wantsOnlyTiled = 1;
prop = prop.substr(1);
} else if (prop.starts_with("f")) {
wantsOnlyTiled = 0;
prop = prop.substr(1);
}
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;
}
return g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled)) == from;
}
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;
}
const auto WINDOWSONWORKSPACE = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional<bool>((bool)wantsOnlyTiled));
if (std::clamp(WINDOWSONWORKSPACE, from, to) != WINDOWSONWORKSPACE)
return false;
continue;
}
Debug::log(LOG, "Invalid selector {}", selector);
return false;
}
return true;
}
UNREACHABLE();
return false;
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "AnimatedVariable.hpp"
#include "../helpers/AnimatedVariable.hpp"
#include <string>
#include "../defines.hpp"
@@ -14,7 +14,7 @@ class CWindow;
class CWorkspace {
public:
CWorkspace(int monitorID, std::string name, bool special = false);
CWorkspace(int id, int monitorID, std::string name, bool special = false);
~CWorkspace();
// Workspaces ID-based have IDs > 0
@@ -35,8 +35,8 @@ class CWorkspace {
wl_array m_wlrCoordinateArr;
// for animations
CAnimatedVariable m_vRenderOffset;
CAnimatedVariable m_fAlpha;
CAnimatedVariable<Vector2D> m_vRenderOffset;
CAnimatedVariable<float> m_fAlpha;
bool m_bForceRendering = false;
// "scratchpad"
@@ -64,4 +64,6 @@ class CWorkspace {
void rememberPrevWorkspace(const CWorkspace* prevWorkspace);
std::string getConfigName();
bool matchesStaticSelector(const std::string& selector);
};

View File

@@ -74,7 +74,7 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
Debug::log(LOG, "Attached a touch device with name {}", DEVICE->name);
g_pInputManager->newTouchDevice(DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET_TOOL:
case WLR_INPUT_DEVICE_TABLET:
Debug::log(LOG, "Attached a tablet tool with name {}", DEVICE->name);
g_pInputManager->newTabletTool(DEVICE);
break;
@@ -97,44 +97,14 @@ void Events::listener_newConstraint(wl_listener* listener, void* data) {
Debug::log(LOG, "New mouse constraint at {:x}", (uintptr_t)PCONSTRAINT);
g_pInputManager->m_lConstraints.emplace_back();
const auto CONSTRAINT = &g_pInputManager->m_lConstraints.back();
const auto SURFACE = CWLSurface::surfaceFromWlr(PCONSTRAINT->surface);
CONSTRAINT->pMouse = g_pCompositor->m_sSeat.mouse;
CONSTRAINT->constraint = PCONSTRAINT;
CONSTRAINT->hyprListener_destroyConstraint.initCallback(&PCONSTRAINT->events.destroy, &Events::listener_destroyConstraint, CONSTRAINT, "Constraint");
CONSTRAINT->hyprListener_setConstraintRegion.initCallback(&PCONSTRAINT->events.set_region, &Events::listener_setConstraintRegion, CONSTRAINT, "Constraint");
if (g_pCompositor->m_pLastFocus == PCONSTRAINT->surface) {
g_pInputManager->constrainMouse(CONSTRAINT->pMouse, PCONSTRAINT);
if (!CONSTRAINT->hintSet)
CONSTRAINT->positionHint = Vector2D{-1, -1};
}
}
void Events::listener_destroyConstraint(void* owner, void* data) {
const auto PCONSTRAINT = (SConstraint*)owner;
if (PCONSTRAINT->pMouse->currentConstraint == PCONSTRAINT->constraint) {
PCONSTRAINT->pMouse->hyprListener_commitConstraint.removeCallback();
const auto PWINDOW = g_pCompositor->getConstraintWindow(g_pCompositor->m_sSeat.mouse);
if (PWINDOW && PCONSTRAINT->active && PCONSTRAINT->constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
g_pInputManager->warpMouseToConstraintMiddle(PCONSTRAINT);
PCONSTRAINT->pMouse->currentConstraint = nullptr;
if (!SURFACE) {
Debug::log(ERR, "Refusing a constraint from an unassigned wl_surface {:x}", (uintptr_t)PCONSTRAINT->surface);
return;
}
Debug::log(LOG, "Unconstrained mouse from {:x}", (uintptr_t)PCONSTRAINT->constraint);
g_pInputManager->m_lConstraints.remove(*PCONSTRAINT);
}
void Events::listener_setConstraintRegion(void* owner, void* data) {
// no
SURFACE->appendConstraint(PCONSTRAINT);
}
void Events::listener_newVirtPtr(wl_listener* listener, void* data) {

View File

@@ -22,25 +22,6 @@ namespace Events {
DYNLISTENFUNC(unmapLayerSurface);
DYNLISTENFUNC(commitLayerSurface);
// Subsurfaces
DYNLISTENFUNC(newSubsurfaceNode);
DYNLISTENFUNC(destroySubsurfaceNode);
DYNLISTENFUNC(mapSubsurface);
DYNLISTENFUNC(unmapSubsurface);
DYNLISTENFUNC(destroySubsurface);
DYNLISTENFUNC(commitSubsurface);
// Popups
DYNLISTENFUNC(newPopup); // LayerSurface
DYNLISTENFUNC(newPopupXDG);
DYNLISTENFUNC(mapPopupXDG);
DYNLISTENFUNC(unmapPopupXDG);
DYNLISTENFUNC(destroyPopupXDG);
DYNLISTENFUNC(commitPopupXDG);
DYNLISTENFUNC(newPopupFromPopupXDG);
DYNLISTENFUNC(repositionPopupXDG);
// Surface XDG (window)
LISTENER(newXDGToplevel);
LISTENER(activateXDG);
@@ -84,10 +65,7 @@ namespace Events {
DYNLISTENFUNC(keyboardMod);
DYNLISTENFUNC(keyboardDestroy);
DYNLISTENFUNC(commitConstraint);
LISTENER(newConstraint);
DYNLISTENFUNC(setConstraintRegion);
DYNLISTENFUNC(destroyConstraint);
// Various
LISTENER(requestMouse);
@@ -148,12 +126,6 @@ namespace Events {
LISTENER(newTextInput);
LISTENER(newVirtualKeyboard);
// IME Popups
DYNLISTENFUNC(mapInputPopup);
DYNLISTENFUNC(unmapInputPopup);
DYNLISTENFUNC(commitInputPopup);
DYNLISTENFUNC(destroyInputPopup);
// Touch
LISTENER(touchBegin);
LISTENER(touchEnd);
@@ -174,4 +146,7 @@ namespace Events {
// Tearing hints
LISTENER(newTearingHint);
// Shortcut inhibitor
LISTENER(newShortcutInhibitor);
};

View File

@@ -46,12 +46,12 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
layerSurface->hyprListener_destroyLayerSurface.initCallback(&WLRLAYERSURFACE->events.destroy, &Events::listener_destroyLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_mapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.map, &Events::listener_mapLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_unmapLayerSurface.initCallback(&WLRLAYERSURFACE->surface->events.unmap, &Events::listener_unmapLayerSurface, layerSurface, "layerSurface");
layerSurface->hyprListener_newPopup.initCallback(&WLRLAYERSURFACE->events.new_popup, &Events::listener_newPopup, layerSurface, "layerSurface");
layerSurface->layerSurface = WLRLAYERSURFACE;
layerSurface->layer = WLRLAYERSURFACE->current.layer;
WLRLAYERSURFACE->data = layerSurface;
layerSurface->monitorID = PMONITOR->ID;
layerSurface->popupHead = std::make_unique<CPopup>(layerSurface);
layerSurface->forceBlur = g_pConfigManager->shouldBlurLS(layerSurface->szNamespace);
@@ -66,6 +66,8 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
layersurface->popupHead.reset();
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID))
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
@@ -87,7 +89,6 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
layersurface->hyprListener_destroyLayerSurface.removeCallback();
layersurface->hyprListener_mapLayerSurface.removeCallback();
layersurface->hyprListener_unmapLayerSurface.removeCallback();
layersurface->hyprListener_newPopup.removeCallback();
// rearrange to fix the reserved areas
if (PMONITOR) {
@@ -113,9 +114,6 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
layersurface->keyboardExclusive = layersurface->layerSurface->current.keyboard_interactive;
layersurface->surface = layersurface->layerSurface->surface;
// anim
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn"));
// fix if it changed its mon
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
@@ -147,15 +145,17 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
// don't focus if constrained
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
(!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained());
if (GRABSFOCUS) {
g_pInputManager->releaseAllMouseButtons();
g_pCompositor->focusSurface(layersurface->layerSurface->surface);
const auto LOCAL =
g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y);
g_pInputManager->m_bEmptyFocusCursorSet = false;
}
layersurface->position = Vector2D(layersurface->geometry.x, layersurface->geometry.y);
@@ -166,8 +166,7 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
const auto WORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
layersurface->alpha.setValue(0);
layersurface->alpha = ((layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS) ? 0.f : 1.f);
layersurface->startAnimation(!(layersurface->layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS));
layersurface->readyToDelete = false;
layersurface->fadingOut = false;
@@ -198,23 +197,17 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
layersurface->mapped = false;
layersurface->fadingOut = true;
layersurface->alpha.setValueAndWarp(0.f);
layersurface->startAnimation(false);
return;
}
// anim
layersurface->alpha.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut"));
// make a snapshot and start fade
g_pHyprOpenGL->makeLayerSnapshot(layersurface);
layersurface->alpha = 0.f;
layersurface->startAnimation(false);
layersurface->mapped = false;
layersurface->fadingOut = true;
g_pCompositor->addToFadingOutSafe(layersurface);
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layersurface->layerSurface->output);
@@ -244,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],
&surfaceCoords, &pFoundLayerSurface);
if (!foundSurface) {
if (!foundSurface && g_pCompositor->m_pLastWindow && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_iWorkspaceID)) {
// if there isn't any, focus the last window
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow;
g_pCompositor->focusWindow(nullptr);
@@ -335,8 +328,20 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
}
}
if (layersurface->layerSurface->current.keyboard_interactive &&
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) // don't focus if constrained
if (layersurface->realPosition.goal() != layersurface->geometry.pos()) {
if (layersurface->realPosition.isBeingAnimated())
layersurface->realPosition = layersurface->geometry.pos();
else
layersurface->realPosition.setValueAndWarp(layersurface->geometry.pos());
}
if (layersurface->realSize.goal() != layersurface->geometry.size()) {
if (layersurface->realSize.isBeingAnimated())
layersurface->realSize = layersurface->geometry.size();
else
layersurface->realSize.setValueAndWarp(layersurface->geometry.size());
}
if (layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained()) // don't focus if constrained
&& !layersurface->keyboardExclusive && layersurface->mapped) {
g_pCompositor->focusSurface(layersurface->layerSurface->surface);
@@ -344,7 +349,8 @@ void Events::listener_commitLayerSurface(void* owner, void* data) {
g_pInputManager->getMouseCoordsInternal() - Vector2D(layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layersurface->layerSurface->surface, LOCAL.x, LOCAL.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y);
} else if (!layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) &&
g_pInputManager->m_bEmptyFocusCursorSet = false;
} else if (!layersurface->layerSurface->current.keyboard_interactive && (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained()) &&
layersurface->keyboardExclusive) {
g_pInputManager->refocus();
}

View File

@@ -4,6 +4,7 @@
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "../managers/CursorManager.hpp"
// ------------------------------ //
// __ __ _____ _____ _____ //
@@ -63,15 +64,26 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
}
ATOM.second = reply->atom;
free(reply);
}
wlr_xwayland_set_seat(g_pXWaylandManager->m_sWLRXWayland, g_pCompositor->m_sSeat.seat);
const auto XCURSOR = wlr_xcursor_manager_get_xcursor(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", 1);
if (XCURSOR) {
wlr_xwayland_set_cursor(g_pXWaylandManager->m_sWLRXWayland, XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, XCURSOR->images[0]->width,
XCURSOR->images[0]->height, XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y);
}
g_pCursorManager->setXWaylandCursor(g_pXWaylandManager->m_sWLRXWayland);
const auto ROOT = xcb_setup_roots_iterator(xcb_get_setup(XCBCONNECTION)).data->root;
auto cookie = xcb_get_property(XCBCONNECTION, 0, ROOT, HYPRATOMS["_NET_SUPPORTING_WM_CHECK"], XCB_ATOM_ANY, 0, 2048);
auto reply = xcb_get_property_reply(XCBCONNECTION, cookie, nullptr);
const auto XWMWINDOW = *(xcb_window_t*)xcb_get_property_value(reply);
const char* name = "Hyprland";
xcb_change_property(wlr_xwayland_get_xwm_connection(g_pXWaylandManager->m_sWLRXWayland), XCB_PROP_MODE_REPLACE, XWMWINDOW, HYPRATOMS["_NET_WM_NAME"], HYPRATOMS["UTF8_STRING"],
8, // format
strlen(name), name);
free(reply);
xcb_disconnect(XCBCONNECTION);
#endif
@@ -128,6 +140,8 @@ void Events::listener_destroyDrag(void* owner, void* data) {
g_pInputManager->m_sDrag.drag = nullptr;
g_pInputManager->m_sDrag.dragIcon = nullptr;
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
g_pCompositor->focusWindow(g_pCompositor->m_pLastWindow, g_pCompositor->m_pLastWindow ? g_pXWaylandManager->getWindowSurface(g_pCompositor->m_pLastWindow) : nullptr);
}
void Events::listener_mapDragIcon(void* owner, void* data) {
@@ -167,6 +181,7 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
for (auto& m : g_pCompositor->m_vMonitors) {
g_pCompositor->scheduleFrameForMonitor(m.get());
g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true);
}
g_pConfigManager->m_bWantsMonitorReload = true;
@@ -231,8 +246,6 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
}
void Events::listener_newTearingHint(wl_listener* listener, void* data) {
const auto TCTL = (wlr_tearing_control_v1*)data;
Debug::log(LOG, "New tearing hint at {:x}", (uintptr_t)data);
const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
@@ -262,3 +275,20 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
},
NEWCTRL, "TearingController");
}
void Events::listener_newShortcutInhibitor(wl_listener* listener, void* data) {
const auto INHIBITOR = (wlr_keyboard_shortcuts_inhibitor_v1*)data;
const auto PINH = &g_pKeybindManager->m_lShortcutInhibitors.emplace_back();
PINH->hyprListener_destroy.initCallback(
&INHIBITOR->events.destroy,
[](void* owner, void* data) {
const auto OWNER = (SShortcutInhibitor*)owner;
g_pKeybindManager->m_lShortcutInhibitors.remove(*OWNER);
},
PINH, "ShortcutInhibitor");
PINH->pWlrInhibitor = INHIBITOR;
Debug::log(LOG, "New shortcut inhibitor for surface {:x}", (uintptr_t)INHIBITOR->surface);
}

View File

@@ -4,6 +4,7 @@
#include "../render/Renderer.hpp"
#include "Events.hpp"
#include "../debug/HyprCtl.hpp"
#include "../config/ConfigValue.hpp"
// --------------------------------------------------------- //
// __ __ ____ _ _ _____ _______ ____ _____ _____ //
@@ -116,6 +117,13 @@ void Events::listener_newOutput(wl_listener* listener, 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;
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
@@ -147,8 +155,8 @@ void Events::listener_monitorFrame(void* owner, void* data) {
PMONITOR->tearingState.frameScheduledWhileBusy = false;
}
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
static auto PENABLERAT = CConfigValue<Hyprlang::INT>("misc:render_ahead_of_time");
static auto PRATSAFE = CConfigValue<Hyprlang::INT>("misc:render_ahead_safezone");
PMONITOR->lastPresentationTimer.reset();
@@ -209,10 +217,20 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
}
void Events::listener_monitorStateRequest(void* owner, void* data) {
//const auto PMONITOR = (CMonitor*)owner;
//const auto E = (wlr_output_event_request_state*)data;
const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_request_state*)data;
// TODO: maybe don't ignore?
if (!PMONITOR->createdByUser)
return;
const auto SIZE = E->state->mode ? Vector2D{E->state->mode->width, E->state->mode->height} : Vector2D{E->state->custom_mode.width, E->state->custom_mode.height};
PMONITOR->forceSize = SIZE;
SMonitorRule rule = PMONITOR->activeMonitorRule;
rule.resolution = SIZE;
g_pHyprRenderer->applyMonitorRule(PMONITOR, &rule);
}
void Events::listener_monitorDamage(void* owner, void* data) {

View File

@@ -1,264 +0,0 @@
#include "Events.hpp"
#include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
// --------------------------------------------- //
// _____ ____ _____ _ _ _____ _____ //
// | __ \ / __ \| __ \| | | | __ \ / ____| //
// | |__) | | | | |__) | | | | |__) | (___ //
// | ___/| | | | ___/| | | | ___/ \___ \ //
// | | | |__| | | | |__| | | ____) | //
// |_| \____/|_| \____/|_| |_____/ //
// //
// --------------------------------------------- //
void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
SXDGPopup* const PPOPUP = (SXDGPopup*)pPopup;
auto curPopup = PPOPUP;
int px = 0;
int py = 0;
while (true) {
px += curPopup->popup->current.geometry.x;
py += curPopup->popup->current.geometry.y;
if (curPopup == PPOPUP && PPOPUP->parentWindow) {
px -= curPopup->popup->base->current.geometry.x;
py -= curPopup->popup->base->current.geometry.y;
}
if (curPopup->popup && !curPopup->parentPopup && !curPopup->parentWindow) {
const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->popup->base->surface->input_region);
px -= EXTENTSSURFACE->x1;
py -= EXTENTSSURFACE->y1;
}
if (curPopup->parentPopup) {
curPopup = curPopup->parentPopup;
} else {
break;
}
}
px += PPOPUP->lx;
py += PPOPUP->ly;
*x += px;
*y += py;
}
void createNewPopup(wlr_xdg_popup* popup, SXDGPopup* pHyprPopup) {
pHyprPopup->popup = popup;
pHyprPopup->hyprListener_destroyPopupXDG.initCallback(&popup->base->events.destroy, &Events::listener_destroyPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_mapPopupXDG.initCallback(&popup->base->surface->events.map, &Events::listener_mapPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_unmapPopupXDG.initCallback(&popup->base->surface->events.unmap, &Events::listener_unmapPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_newPopupFromPopupXDG.initCallback(&popup->base->events.new_popup, &Events::listener_newPopupFromPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_commitPopupXDG.initCallback(&popup->base->surface->events.commit, &Events::listener_commitPopupXDG, pHyprPopup, "HyprPopup");
pHyprPopup->hyprListener_repositionPopupXDG.initCallback(&popup->events.reposition, &Events::listener_repositionPopupXDG, pHyprPopup, "HyprPopup");
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
CBox box = {PMONITOR->vecPosition.x - pHyprPopup->lx, PMONITOR->vecPosition.y - pHyprPopup->ly, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(popup, box.pWlr());
pHyprPopup->monitor = PMONITOR;
Debug::log(LOG, "Popup: Unconstrained from lx ly: {:j5}, pHyprPopup lx ly: {:.5f} {:.5f}", PMONITOR->vecPosition, (float)pHyprPopup->lx, (float)pHyprPopup->ly);
}
void Events::listener_newPopup(void* owner, void* data) {
SLayerSurface* layersurface = (SLayerSurface*)owner;
ASSERT(layersurface);
Debug::log(LOG, "New layer popup created from surface {:x}", (uintptr_t)layersurface);
const auto WLRPOPUP = (wlr_xdg_popup*)data;
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
PNEWPOPUP->popup = WLRPOPUP;
PNEWPOPUP->lx = layersurface->position.x;
PNEWPOPUP->ly = layersurface->position.y;
PNEWPOPUP->monitor = PMONITOR;
PNEWPOPUP->parentLS = layersurface;
createNewPopup(WLRPOPUP, PNEWPOPUP);
}
void Events::listener_newPopupXDG(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
ASSERT(PWINDOW);
if (!PWINDOW->m_bIsMapped)
return;
Debug::log(LOG, "New layer popup created from XDG window {}", PWINDOW);
const auto WLRPOPUP = (wlr_xdg_popup*)data;
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
PNEWPOPUP->popup = WLRPOPUP;
PNEWPOPUP->lx = PWINDOW->m_vRealPosition.goalv().x;
PNEWPOPUP->ly = PWINDOW->m_vRealPosition.goalv().y;
PNEWPOPUP->parentWindow = PWINDOW;
PNEWPOPUP->monitor = PMONITOR;
createNewPopup(WLRPOPUP, PNEWPOPUP);
}
void Events::listener_newPopupFromPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
ASSERT(PPOPUP);
if (PPOPUP->parentWindow)
Debug::log(LOG, "New popup created from XDG Window popup {:x} -> {}", (uintptr_t)PPOPUP, PPOPUP->parentWindow);
else
Debug::log(LOG, "New popup created from Non-Window popup {:x}", (uintptr_t)PPOPUP);
const auto WLRPOPUP = (wlr_xdg_popup*)data;
const auto PNEWPOPUP = g_pCompositor->m_vXDGPopups.emplace_back(std::make_unique<SXDGPopup>()).get();
PNEWPOPUP->popup = WLRPOPUP;
PNEWPOPUP->parentPopup = PPOPUP;
PNEWPOPUP->lx = PPOPUP->lx;
PNEWPOPUP->ly = PPOPUP->ly;
PNEWPOPUP->parentWindow = PPOPUP->parentWindow;
PNEWPOPUP->monitor = PPOPUP->monitor;
createNewPopup(WLRPOPUP, PNEWPOPUP);
}
void Events::listener_mapPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
ASSERT(PPOPUP);
Debug::log(LOG, "New XDG Popup mapped at {} {}", (int)PPOPUP->lx, (int)PPOPUP->ly);
if (PPOPUP->parentWindow)
PPOPUP->parentWindow->m_lPopupSurfaces.emplace_back(PPOPUP->popup->base->surface);
else if (PPOPUP->parentLS)
PPOPUP->parentLS->popupSurfaces.emplace_back(PPOPUP->popup->base->surface);
PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow);
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
if (PPOPUP->monitor) {
g_pCompositor->setPreferredScaleForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->scale);
g_pCompositor->setPreferredTransformForSurface(PPOPUP->popup->base->surface, PPOPUP->monitor->transform);
}
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode {:x}", (uintptr_t)PPOPUP->pSurfaceTree);
}
void Events::listener_repositionPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
Debug::log(LOG, "XDG Popup {:x} asks for a reposition", (uintptr_t)PPOPUP);
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
PPOPUP->lastPos = {lx - extents.x, ly - extents.y};
PPOPUP->repositionRequested = true;
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
CBox box = {PMONITOR->vecPosition.x - lx + PPOPUP->popup->current.geometry.x, PMONITOR->vecPosition.y - ly + PPOPUP->popup->current.geometry.y, PMONITOR->vecSize.x,
PMONITOR->vecSize.y};
wlr_xdg_popup_unconstrain_from_box(PPOPUP->popup, box.pWlr());
}
void Events::listener_unmapPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
Debug::log(LOG, "XDG Popup unmapped");
ASSERT(PPOPUP);
if (PPOPUP->popup->base->surface == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons();
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
g_pHyprRenderer->damageBox(lx - extents.x, ly - extents.y, extents.width + 2, extents.height + 2);
if (PPOPUP->parentWindow)
std::erase(PPOPUP->parentWindow->m_lPopupSurfaces, PPOPUP->popup->base->surface);
else if (PPOPUP->parentLS)
std::erase(PPOPUP->parentLS->popupSurfaces, PPOPUP->popup->base->surface);
PPOPUP->pSurfaceTree = nullptr;
g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface
}
void Events::listener_commitPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
if (g_pCompositor->windowValidMapped(PPOPUP->parentWindow)) {
PPOPUP->lx = PPOPUP->parentWindow->m_vRealPosition.vec().x;
PPOPUP->ly = PPOPUP->parentWindow->m_vRealPosition.vec().y;
}
int lx = 0, ly = 0;
addPopupGlobalCoords(PPOPUP, &lx, &ly);
CBox extents;
wlr_surface_get_extends(PPOPUP->popup->base->surface, extents.pWlr());
extents.applyFromWlr();
if (PPOPUP->repositionRequested)
g_pHyprRenderer->damageBox(PPOPUP->lastPos.x, PPOPUP->lastPos.y, extents.width + 2, extents.height + 2);
PPOPUP->repositionRequested = false;
g_pHyprRenderer->damageSurface(PPOPUP->popup->base->surface, lx, ly);
}
void Events::listener_destroyPopupXDG(void* owner, void* data) {
SXDGPopup* PPOPUP = (SXDGPopup*)owner;
ASSERT(PPOPUP);
Debug::log(LOG, "Destroyed popup XDG {:x}", (uintptr_t)PPOPUP);
if (PPOPUP->pSurfaceTree) {
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
PPOPUP->pSurfaceTree = nullptr;
}
std::erase_if(g_pCompositor->m_vXDGPopups, [&](std::unique_ptr<SXDGPopup>& el) { return el.get() == PPOPUP; });
}

View File

@@ -4,6 +4,7 @@
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "../config/ConfigValue.hpp"
// ------------------------------------------------------------ //
// __ _______ _ _ _____ ______ _______ //
@@ -17,8 +18,8 @@
void addViewCoords(void* pWindow, int* x, int* y) {
const auto PWINDOW = (CWindow*)pWindow;
*x += PWINDOW->m_vRealPosition.goalv().x;
*y += PWINDOW->m_vRealPosition.goalv().y;
*x += PWINDOW->m_vRealPosition.goal().x;
*y += PWINDOW->m_vRealPosition.goal().y;
if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) {
wlr_box geom;
@@ -32,25 +33,31 @@ void addViewCoords(void* pWindow, int* x, int* y) {
void setAnimToMove(void* data) {
auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove");
CAnimatedVariable* animvar = (CAnimatedVariable*)data;
CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data;
if (animvar->getWindow() && !animvar->getWindow()->m_vRealPosition.isBeingAnimated() && !animvar->getWindow()->m_vRealSize.isBeingAnimated()) {
animvar->setConfig(PANIMCFG);
animvar->getWindow()->m_bAnimatingIn = false;
}
}
void Events::listener_mapWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
static auto* const PINACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:inactive_opacity")->floatValue;
static auto* const PACTIVEALPHA = &g_pConfigManager->getConfigValuePtr("decoration:active_opacity")->floatValue;
static auto* const PDIMSTRENGTH = &g_pConfigManager->getConfigValuePtr("decoration:dim_strength")->floatValue;
static auto* const PSWALLOW = &g_pConfigManager->getConfigValuePtr("misc:enable_swallow")->intValue;
static auto* const PSWALLOWREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_regex")->strValue;
static auto* const PSWALLOWEXREGEX = &g_pConfigManager->getConfigValuePtr("misc:swallow_exception_regex")->strValue;
static auto* const PNEWTAKESOVERFS = &g_pConfigManager->getConfigValuePtr("misc:new_window_takes_over_fullscreen")->intValue;
static auto PINACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:inactive_opacity");
static auto PACTIVEALPHA = CConfigValue<Hyprlang::FLOAT>("decoration:active_opacity");
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
static auto PSWALLOWREGEX = CConfigValue<std::string>("misc:swallow_regex");
static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex");
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen");
auto PMONITOR = g_pCompositor->m_pLastMonitor;
const 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->specialWorkspaceID ? g_pCompositor->getWorkspaceByID(PMONITOR->specialWorkspaceID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
PWINDOW->m_iMonitorID = PMONITOR->ID;
PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceID ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
PWINDOW->m_bIsMapped = true;
@@ -101,7 +108,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
// window rules
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW, false);
std::string requestedWorkspace = "";
bool workspaceSilent = false;
bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen ||
@@ -173,13 +180,23 @@ void Events::listener_mapWindow(void* owner, void* data) {
} else if (r.szRule.starts_with("pseudo")) {
PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.starts_with("nofocus")) {
PWINDOW->m_bNoFocus = true;
PWINDOW->m_sAdditionalConfigData.noFocus = true;
} else if (r.szRule.starts_with("noinitialfocus")) {
PWINDOW->m_bNoInitialFocus = true;
} else if (r.szRule.starts_with("nofullscreenrequest")) {
PWINDOW->m_bNoFullscreenRequest = true;
} else if (r.szRule.starts_with("nomaximizerequest")) {
PWINDOW->m_bNoMaximizeRequest = true;
} else if (r.szRule.starts_with("suppressevent")) {
CVarList vars(r.szRule, 0, 's', true);
for (size_t i = 1; i < vars.size(); ++i) {
if (vars[i] == "fullscreen")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN;
else if (vars[i] == "maximize")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_MAXIMIZE;
else if (vars[i] == "activate")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE;
else if (vars[i] == "activatefocus")
PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY;
else
Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]);
}
} else if (r.szRule == "fullscreen") {
requestsFullscreen = true;
overridingNoFullscreen = true;
@@ -249,8 +266,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->applyDynamicRule(r);
}
PWINDOW->updateSpecialRenderData();
// disallow tiled pinned
if (PWINDOW->m_bPinned && !PWINDOW->m_bIsFloating)
PWINDOW->m_bPinned = false;
@@ -270,6 +285,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!pWorkspace)
pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName);
PWORKSPACE = pWorkspace;
PWINDOW->m_iWorkspaceID = pWorkspace->m_iID;
PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID;
@@ -279,7 +296,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (!workspaceSilent) {
if (pWorkspace->m_bIsSpecialWorkspace)
g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID)->setSpecialWorkspace(pWorkspace);
else
else if (PMONITOR->activeWorkspace != REQUESTEDWORKSPACEID)
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
PMONITOR = g_pCompositor->m_pLastMonitor;
@@ -288,6 +305,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
workspaceSilent = false;
}
PWINDOW->updateSpecialRenderData();
if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
PWINDOW->m_bCreatedOverFullscreen = true;
@@ -312,38 +331,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
Debug::log(LOG, "Rule size, applying to {}", PWINDOW);
PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("minsize")) {
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 SIZE =
Vector2D(std::max((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::max((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goalv().y));
PWINDOW->m_vRealSize = SIZE;
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule minsize failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("maxsize")) {
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 SIZE =
Vector2D(std::min((double)std::stoll(SIZEXSTR), PWINDOW->m_vRealSize.goalv().x), std::min((double)std::stoll(SIZEYSTR), PWINDOW->m_vRealSize.goalv().y));
PWINDOW->m_vRealSize = SIZE;
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
PWINDOW->setHidden(false);
} catch (...) { Debug::log(LOG, "Rule maxsize failed, rule: {} -> {}", r.szRule, r.szValue); }
} else if (r.szRule.starts_with("move")) {
try {
auto value = r.szRule.substr(r.szRule.find(' ') + 1);
@@ -379,7 +370,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x;
} else {
posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x +
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().x);
(!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x);
}
}
@@ -398,7 +389,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y;
} else {
posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y +
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goalv().y);
(!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y);
}
}
@@ -406,10 +397,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
int borderSize = PWINDOW->getRealBorderSize();
posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize),
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goalv().x - borderSize));
(int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize));
posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize),
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goalv().y - borderSize));
(int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize));
}
Debug::log(LOG, "Rule move, applying to {}", PWINDOW);
@@ -424,26 +415,26 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (ARGS[1] == "1")
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goalv() / 2.f + RESERVEDOFFSET;
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET;
}
}
// set the pseudo size to the GOAL of our current size
// because the windows are animated on RealSize
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv();
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal();
g_pCompositor->changeWindowZOrder(PWINDOW, true);
} else {
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
// Set the pseudo size here too so that it doesnt end up being 0x0
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10, 10);
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10);
}
const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow;
if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) {
PWINDOW->m_bNoFocus = false;
PWINDOW->m_sAdditionalConfigData.noFocus = false;
PWINDOW->m_bNoInitialFocus = false;
PWINDOW->m_bX11ShouldntFocus = false;
}
@@ -464,9 +455,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
requestsFullscreen = true;
}
if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus &&
(PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && !workspaceSilent &&
(!PFORCEFOCUS || PFORCEFOCUS == PWINDOW)) {
if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus &&
(PWINDOW->m_iX11Type != 2 ||
(PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->window_type_len > 0 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) &&
!workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) {
g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA);
PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH);
@@ -475,11 +467,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_fDimPercent.setValueAndWarp(0);
}
Debug::log(LOG, "Window got assigned a surfaceTreeNode {:x}", (uintptr_t)PWINDOW->m_pSurfaceTree);
if (!PWINDOW->m_bIsX11) {
PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_newPopupXDG.initCallback(&PWINDOW->m_uSurface.xdg->events.new_popup, &Events::listener_newPopupXDG, PWINDOW, "XDG Window Late");
PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW,
"XDG Window Late");
PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW,
@@ -504,8 +493,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
"XWayland Window Late");
}
if ((requestsFullscreen && (!PWINDOW->m_bNoFullscreenRequest || overridingNoFullscreen)) || (requestsMaximize && (!PWINDOW->m_bNoMaximizeRequest || overridingNoMaximize)) ||
requestsFakeFullscreen) {
if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) ||
(requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) {
// fix fullscreen on requested (basically do a switcheroo)
if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
@@ -527,8 +516,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
// recheck idle inhibitors
g_pInputManager->recheckIdleInhibitorStatus();
PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(PWINDOW->m_pWLSurface.wlr(), addViewCoords, PWINDOW, PWINDOW);
PWINDOW->updateToplevel();
if (workspaceSilent) {
@@ -540,7 +527,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
}
// verify swallowing
if (*PSWALLOW && *PSWALLOWREGEX != STRVAL_EMPTY) {
if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) {
// don't swallow ourselves
std::regex rgx(*PSWALLOWREGEX);
if (!std::regex_match(g_pXWaylandManager->getAppIDClass(PWINDOW), rgx)) {
@@ -587,7 +574,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (finalFound) {
bool valid = std::regex_match(g_pXWaylandManager->getAppIDClass(finalFound), rgx);
if (*PSWALLOWEXREGEX != STRVAL_EMPTY) {
if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) {
std::regex exc(*PSWALLOWEXREGEX);
valid = valid && !std::regex_match(g_pXWaylandManager->getTitle(finalFound), exc);
@@ -611,7 +598,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bFirstMap = false;
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goalv(), PWINDOW->m_vRealSize.goalv());
Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goal(), PWINDOW->m_vRealSize.goal());
auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName;
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, g_pXWaylandManager->getAppIDClass(PWINDOW), PWINDOW->m_szTitle)});
@@ -639,13 +626,16 @@ void Events::listener_mapWindow(void* owner, void* data) {
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->constraintActive)
if (!g_pCompositor->m_sSeat.mouse || !g_pInputManager->isConstrained())
g_pInputManager->sendMotionEventsToFocused();
// fix some xwayland apps that don't behave nicely
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
if (PMONITOR && PWINDOW->m_iX11Type == 2)
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
}
void Events::listener_unmapWindow(void* owner, void* data) {
@@ -661,8 +651,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR) {
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.vec() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.vec();
PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition;
PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value();
PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents();
}
@@ -674,7 +664,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (!PWINDOW->m_bIsX11) {
Debug::log(LOG, "Unregistered late callbacks XDG");
PWINDOW->hyprListener_setTitleWindow.removeCallback();
PWINDOW->hyprListener_newPopupXDG.removeCallback();
PWINDOW->hyprListener_requestMaximize.removeCallback();
PWINDOW->hyprListener_requestMinimize.removeCallback();
PWINDOW->hyprListener_requestMove.removeCallback();
@@ -734,6 +723,9 @@ void Events::listener_unmapWindow(void* owner, void* data) {
if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow && PWINDOWCANDIDATE)
g_pCompositor->focusWindow(PWINDOWCANDIDATE);
if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->m_iWorkspaceID) == 0)
g_pInputManager->refocus();
g_pInputManager->sendMotionEventsToFocused();
// CWindow::onUnmap will remove this window's active status, but we can't really do it above.
@@ -746,11 +738,6 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "Unmapped was not focused, ignoring a refocus.");
}
Debug::log(LOG, "Destroying the SubSurface tree of unmapped window {}", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
PWINDOW->m_pSurfaceTree = nullptr;
PWINDOW->m_bFadingOut = true;
g_pCompositor->addToFadingOutSafe(PWINDOW);
@@ -758,7 +745,7 @@ void Events::listener_unmapWindow(void* owner, void* data) {
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID));
if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in.
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.vec() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it
// anims
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true);
@@ -794,6 +781,15 @@ void Events::listener_ackConfigure(void* owner, void* data) {
void Events::listener_commitWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner;
if (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->initial_commit) {
Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow(PWINDOW);
Debug::log(LOG, "Layout predicts size {} for {}", predSize, PWINDOW);
wlr_xdg_toplevel_set_size(PWINDOW->m_uSurface.xdg->toplevel, predSize.x, predSize.y);
return;
}
if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden())
return;
@@ -804,9 +800,30 @@ void Events::listener_commitWindow(void* owner, void* data) {
PWINDOW->m_pPendingSizeAck.reset();
}
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().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);
if (!PWINDOW->m_bIsX11) {
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
PWINDOW->m_pPopupHead->recheckTree();
}
// tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear &&
PWINDOW->m_pWLSurface.wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
CRegion damageBox{&PWINDOW->m_pWLSurface.wlr()->buffer_damage};
if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) {
PMONITOR->tearingState.frameScheduledWhileBusy = true;
} else {
PMONITOR->tearingState.nextRenderTorn = true;
g_pHyprRenderer->renderMonitor(PMONITOR);
}
}
}
if (PWINDOW->m_bIsX11 || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen)
return;
@@ -816,7 +833,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
if (MAXSIZE < Vector2D{1, 1})
return;
const auto REALSIZE = PWINDOW->m_vRealSize.goalv();
const auto REALSIZE = PWINDOW->m_vRealSize.goal();
Vector2D newSize = REALSIZE;
if (MAXSIZE.x < newSize.x)
@@ -830,7 +847,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
const Vector2D DELTA = REALSIZE - newSize;
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0;
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0;
PWINDOW->m_vRealSize = newSize;
g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true);
g_pHyprRenderer->damageWindow(PWINDOW);
@@ -849,6 +866,8 @@ void Events::listener_destroyWindow(void* owner, void* data) {
g_pCompositor->m_pLastFocus = nullptr;
}
PWINDOW->m_pWLSurface.unassign();
PWINDOW->hyprListener_commitWindow.removeCallback();
PWINDOW->hyprListener_mapWindow.removeCallback();
PWINDOW->hyprListener_unmapWindow.removeCallback();
@@ -860,14 +879,10 @@ void Events::listener_destroyWindow(void* owner, void* data) {
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
if (PWINDOW->m_pSurfaceTree) {
Debug::log(LOG, "Destroying Subsurface tree of {} in destroyWindow", PWINDOW);
SubsurfaceTree::destroySurfaceTree(PWINDOW->m_pSurfaceTree);
PWINDOW->m_pSurfaceTree = nullptr;
}
PWINDOW->m_bReadyToDelete = true;
PWINDOW->m_uSurface.xdg = nullptr;
if (!PWINDOW->m_bFadingOut) {
Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW);
g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn
@@ -880,7 +895,12 @@ void Events::listener_setTitleWindow(void* owner, void* data) {
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
const auto NEWTITLE = g_pXWaylandManager->getTitle(PWINDOW);
if (NEWTITLE == PWINDOW->m_szTitle)
return;
PWINDOW->m_szTitle = NEWTITLE;
g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)PWINDOW)});
EMIT_HOOK_EVENT("windowTitle", PWINDOW);
@@ -905,7 +925,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
return;
}
if (PWINDOW->isHidden() || PWINDOW->m_bNoFullscreenRequest)
if (PWINDOW->isHidden() || (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN))
return;
bool requestedFullState = false;
@@ -959,7 +979,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
void Events::listener_activateXDG(wl_listener* listener, void* data) {
const auto E = (wlr_xdg_activation_v1_request_activate_event*)data;
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
static auto PFOCUSONACTIVATE = CConfigValue<Hyprlang::INT>("misc:focus_on_activate");
Debug::log(LOG, "Activate request for surface at {:x}", (uintptr_t)E->surface);
@@ -968,7 +988,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
const auto PWINDOW = g_pCompositor->getWindowFromSurface(E->surface);
if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow)
if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE))
return;
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
@@ -976,7 +996,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
PWINDOW->m_bIsUrgent = true;
if (!*PFOCUSONACTIVATE)
if (!*PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY))
return;
if (PWINDOW->m_bIsFloating)
@@ -989,7 +1009,7 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) {
void Events::listener_activateX11(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner;
static auto* const PFOCUSONACTIVATE = &g_pConfigManager->getConfigValuePtr("misc:focus_on_activate")->intValue;
static auto PFOCUSONACTIVATE = CConfigValue<Hyprlang::INT>("misc:focus_on_activate");
Debug::log(LOG, "X11 Activate request for window {}", PWINDOW);
@@ -1000,17 +1020,20 @@ void Events::listener_activateX11(void* owner, void* data) {
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID())
return;
if (!wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))
return;
g_pCompositor->focusWindow(PWINDOW);
return;
}
if (PWINDOW == g_pCompositor->m_pLastWindow)
if (PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE))
return;
g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)});
EMIT_HOOK_EVENT("urgent", PWINDOW);
if (!*PFOCUSONACTIVATE)
if (!*PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY))
return;
if (PWINDOW->m_bIsFloating)
@@ -1029,13 +1052,15 @@ void Events::listener_configureX11(void* owner, void* data) {
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
PWINDOW->m_vPendingReportedSize = {E->width, E->height};
PWINDOW->m_vReportedSize = {E->width, E->height};
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
return;
}
g_pHyprRenderer->damageWindow(PWINDOW);
if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == PWINDOW) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
g_pInputManager->refocus();
g_pHyprRenderer->damageWindow(PWINDOW);
return;
@@ -1051,14 +1076,16 @@ void Events::listener_configureX11(void* owner, void* data) {
PWINDOW->m_vRealPosition.setValueAndWarp(LOGICALPOS);
PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height));
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale;
}
}
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
PWINDOW->m_vSize = PWINDOW->m_vRealSize.vec();
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.value();
PWINDOW->m_vSize = PWINDOW->m_vRealSize.value();
wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height);
@@ -1070,7 +1097,7 @@ void Events::listener_configureX11(void* owner, void* data) {
if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_iWorkspaceID))
return; // further things are only for visible windows
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(PWINDOW, true);
@@ -1088,8 +1115,8 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
if (!PWINDOW->m_bIsMapped)
return;
const auto POS = PWINDOW->m_vRealPosition.goalv();
const auto SIZ = PWINDOW->m_vRealSize.goalv();
const auto POS = PWINDOW->m_vRealPosition.goal();
const auto SIZ = PWINDOW->m_vRealSize.goal();
if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1)
PWINDOW->setHidden(false);
@@ -1097,12 +1124,12 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
PWINDOW->setHidden(true);
if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) {
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv(), true);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true);
g_pHyprRenderer->damageWindow(PWINDOW);
return;
}
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y});
@@ -1119,23 +1146,23 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
if (*PXWLFORCESCALEZERO) {
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
const Vector2D DELTA = PWINDOW->m_vRealSize.goal() - PWINDOW->m_vRealSize.goal() / PMONITOR->scale;
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale);
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goal() + DELTA / 2.0);
}
}
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
PWINDOW->m_vSize = PWINDOW->m_vRealSize.goalv();
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal();
PWINDOW->m_vSize = PWINDOW->m_vRealSize.goal();
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.vec() + PWINDOW->m_vRealSize.vec() / 2.f)->activeWorkspace;
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace;
g_pCompositor->changeWindowZOrder(PWINDOW, true);
PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW);
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goalv();
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goalv();
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goal();
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal();
}
}
@@ -1152,11 +1179,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_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) {
const auto PWINDOW = (CWindow*)owner;
PWINDOW->m_pWLSurface.unassign();
PWINDOW->hyprListener_mapWindow.removeCallback();
PWINDOW->hyprListener_commitWindow.removeCallback();
}
@@ -1196,6 +1227,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_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->m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(PNEWWINDOW), PNEWWINDOW);
}
void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
@@ -1206,7 +1239,7 @@ void Events::listener_NewXDGDeco(wl_listener* listener, void* data) {
void Events::listener_requestMaximize(void* owner, void* data) {
const auto PWINDOW = (CWindow*)owner;
if (PWINDOW->m_bNoMaximizeRequest)
if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)
return;
Debug::log(LOG, "Maximize request for {}", PWINDOW);

View File

@@ -2,12 +2,11 @@
#include "../managers/AnimationManager.hpp"
#include "../config/ConfigManager.hpp"
CAnimatedVariable::CAnimatedVariable() {
CBaseAnimatedVariable::CBaseAnimatedVariable(ANIMATEDVARTYPE type) : m_Type(type) {
; // dummy var
}
void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
m_eVarType = type;
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, CWindow* pWindow, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pWindow = pWindow;
@@ -15,42 +14,34 @@ void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* p
m_bDummy = false;
}
void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
create(type, pAnimConfig, pWindow, policy);
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, SLayerSurface* pLayer, AVARDAMAGEPOLICY policy) {
m_eDamagePolicy = policy;
m_pConfig = pAnimConfig;
m_pLayer = pLayer;
try {
switch (type) {
case AVARTYPE_FLOAT: {
const auto V = std::any_cast<float>(val);
m_fValue = V;
m_fGoal = V;
break;
}
case AVARTYPE_VECTOR: {
const auto V = std::any_cast<Vector2D>(val);
m_vValue = V;
m_vGoal = V;
break;
}
case AVARTYPE_COLOR: {
const auto V = std::any_cast<CColor>(val);
m_cValue = V;
m_cGoal = V;
break;
}
default: ASSERT(false); break;
}
} catch (std::exception& e) {
Debug::log(ERR, "CAnimatedVariable create error: {}", e.what());
RASSERT(false, "CAnimatedVariable create error: {}", e.what());
}
m_bDummy = false;
}
CAnimatedVariable::~CAnimatedVariable() {
void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, CWorkspace* 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() {
unregister();
}
void CAnimatedVariable::unregister() {
void CBaseAnimatedVariable::unregister() {
if (!g_pAnimationManager)
return;
std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; });
@@ -58,23 +49,26 @@ void CAnimatedVariable::unregister() {
disconnectFromActive();
}
void CAnimatedVariable::registerVar() {
void CBaseAnimatedVariable::registerVar() {
if (!m_bIsRegistered)
g_pAnimationManager->m_vAnimatedVariables.push_back(this);
m_bIsRegistered = true;
}
int CAnimatedVariable::getDurationLeftMs() {
int CBaseAnimatedVariable::getDurationLeftMs() {
return std::max(
(int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count(), 0);
}
float CAnimatedVariable::getPercent() {
float CBaseAnimatedVariable::getPercent() {
const auto DURATIONPASSED = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - animationBegin).count();
return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
}
float CAnimatedVariable::getCurveValue() {
float CBaseAnimatedVariable::getCurveValue() {
if (!m_bIsBeingAnimated)
return 1.f;
const auto SPENT = getPercent();
if (SPENT >= 1.f)
@@ -83,7 +77,7 @@ float CAnimatedVariable::getCurveValue() {
return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT);
}
void CAnimatedVariable::connectToActive() {
void CBaseAnimatedVariable::connectToActive() {
g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up
if (!m_bIsConnectedToActive)
@@ -92,7 +86,7 @@ void CAnimatedVariable::connectToActive() {
m_bIsConnectedToActive = true;
}
void CAnimatedVariable::disconnectFromActive() {
void CBaseAnimatedVariable::disconnectFromActive() {
std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; });
m_bIsConnectedToActive = false;
}

View File

@@ -3,6 +3,7 @@
#include <functional>
#include <any>
#include <chrono>
#include <type_traits>
#include "Vector2D.hpp"
#include "Color.hpp"
#include "../macros.hpp"
@@ -15,6 +16,30 @@ enum ANIMATEDVARTYPE {
AVARTYPE_COLOR
};
// Utility to bind a type with its corresponding ANIMATEDVARTYPE
template <class T>
struct typeToANIMATEDVARTYPE_t {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_INVALID;
};
template <>
struct typeToANIMATEDVARTYPE_t<float> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_FLOAT;
};
template <>
struct typeToANIMATEDVARTYPE_t<Vector2D> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_VECTOR;
};
template <>
struct typeToANIMATEDVARTYPE_t<CColor> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_COLOR;
};
template <class T>
inline constexpr ANIMATEDVARTYPE typeToANIMATEDVARTYPE = typeToANIMATEDVARTYPE_t<T>::value;
enum AVARDAMAGEPOLICY {
AVARDAMAGE_NONE = -1,
AVARDAMAGE_ENTIRE = 0,
@@ -27,175 +52,39 @@ class CWorkspace;
struct SLayerSurface;
struct SAnimationPropertyConfig;
class CHyprRenderer;
class CWindow;
class CAnimatedVariable {
// Utility to define a concept as a list of possible type
template <class T, class... U>
concept OneOf = (... or std::same_as<T, U>);
// Concept to describe which type can be placed into CAnimatedVariable
// This is mainly to get better errors if we put a type that's not supported
// Otherwise template errors are ugly
template <class T>
concept Animable = OneOf<T, Vector2D, float, CColor>;
class CBaseAnimatedVariable {
public:
CAnimatedVariable(); // dummy var
CBaseAnimatedVariable(ANIMATEDVARTYPE type);
void create(SAnimationPropertyConfig* pAnimConfig, CWindow* pWindow, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, SLayerSurface* pLayer, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, CWorkspace* pWorkspace, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy);
void create(ANIMATEDVARTYPE, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
void create(ANIMATEDVARTYPE, std::any val, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY);
CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
CBaseAnimatedVariable& operator=(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable& operator=(CBaseAnimatedVariable&&) = delete;
CAnimatedVariable(const CAnimatedVariable&) = delete;
CAnimatedVariable(CAnimatedVariable&&) = delete;
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
~CAnimatedVariable();
virtual ~CBaseAnimatedVariable();
void unregister();
void registerVar();
// gets the current vector value (real time)
const Vector2D& vec() const {
return m_vValue;
}
// gets the current float value (real time)
const float& fl() const {
return m_fValue;
}
// gets the current color value (real time)
const CColor& col() const {
return m_cValue;
}
// gets the goal vector value
const Vector2D& goalv() const {
return m_vGoal;
}
// gets the goal float value
const float& goalf() const {
return m_fGoal;
}
// gets the goal color value
const CColor& goalc() const {
return m_cGoal;
}
CAnimatedVariable& operator=(const Vector2D& v) {
if (v == m_vGoal)
return *this;
m_vGoal = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
return *this;
}
CAnimatedVariable& operator=(const float& v) {
if (v == m_fGoal)
return *this;
m_fGoal = v;
animationBegin = std::chrono::system_clock::now();
m_fBegun = m_fValue;
onAnimationBegin();
return *this;
}
CAnimatedVariable& operator=(const CColor& v) {
if (v == m_cGoal)
return *this;
m_cGoal = v;
animationBegin = std::chrono::system_clock::now();
m_cBegun = m_cValue;
onAnimationBegin();
return *this;
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const Vector2D& v) {
if (v == m_vValue)
return;
m_vValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const float& v) {
if (v == m_fValue)
return;
m_fValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const CColor& v) {
if (v == m_cValue)
return;
m_cValue = v;
animationBegin = std::chrono::system_clock::now();
m_vBegun = m_vValue;
onAnimationBegin();
}
// Sets the actual value and goal
void setValueAndWarp(const Vector2D& v) {
m_vGoal = v;
warp();
}
// Sets the actual value and goal
void setValueAndWarp(const float& v) {
m_fGoal = v;
warp();
}
// Sets the actual value and goal
void setValueAndWarp(const CColor& v) {
m_cGoal = v;
warp();
}
// checks if an animation is in progress
inline bool isBeingAnimated() {
return m_bIsBeingAnimated;
}
void warp(bool endCallback = true) {
switch (m_eVarType) {
case AVARTYPE_FLOAT: {
m_fValue = m_fGoal;
break;
}
case AVARTYPE_VECTOR: {
m_vValue = m_vGoal;
break;
}
case AVARTYPE_COLOR: {
m_cValue = m_cGoal;
break;
}
default: UNREACHABLE();
}
m_bIsBeingAnimated = false;
if (endCallback)
onAnimationEnd();
}
virtual void warp(bool endCallback = true) = 0;
//
void setConfig(SAnimationPropertyConfig* pConfig) {
m_pConfig = pConfig;
}
@@ -212,6 +101,11 @@ class CAnimatedVariable {
/* returns the current curve value */
float getCurveValue();
// checks if an animation is in progress
inline bool isBeingAnimated() {
return m_bIsBeingAnimated;
}
/* sets a function to be ran when the animation finishes.
if an animation is not running, runs instantly.
if "remove" is set to true, will remove the callback when ran. */
@@ -245,20 +139,11 @@ class CAnimatedVariable {
m_bRemoveEndAfterRan = false;
}
private:
Vector2D m_vValue = Vector2D(0, 0);
float m_fValue = 0;
CColor m_cValue;
CWindow* getWindow() {
return (CWindow*)m_pWindow;
}
Vector2D m_vGoal = Vector2D(0, 0);
float m_fGoal = 0;
CColor m_cGoal;
Vector2D m_vBegun = Vector2D(0, 0);
float m_fBegun = 0;
CColor m_cBegun;
// owners
protected:
void* m_pWindow = nullptr;
void* m_pWorkspace = nullptr;
void* m_pLayer = nullptr;
@@ -271,8 +156,8 @@ class CAnimatedVariable {
std::chrono::system_clock::time_point animationBegin;
ANIMATEDVARTYPE m_eVarType = AVARTYPE_INVALID;
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE;
ANIMATEDVARTYPE m_Type;
bool m_bRemoveEndAfterRan = true;
bool m_bRemoveBeginAfterRan = true;
@@ -281,7 +166,9 @@ class CAnimatedVariable {
std::function<void(void* thisptr)> m_fUpdateCallback;
bool m_bIsConnectedToActive = false;
void connectToActive();
void disconnectFromActive();
// methods
@@ -314,3 +201,108 @@ class CAnimatedVariable {
friend struct SLayerSurface;
friend class CHyprRenderer;
};
template <Animable VarType>
class CAnimatedVariable : public CBaseAnimatedVariable {
public:
CAnimatedVariable() : CBaseAnimatedVariable(typeToANIMATEDVARTYPE<VarType>) {} // dummy var
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, CWindow* pWindow, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pWindow, policy);
m_Value = 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, CWorkspace* 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;
CAnimatedVariable(const CAnimatedVariable&) = delete;
CAnimatedVariable(CAnimatedVariable&&) = delete;
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
~CAnimatedVariable() = default;
// gets the current vector value (real time)
const VarType& value() const {
return m_Value;
}
// gets the goal vector value
const VarType& goal() const {
return m_Goal;
}
CAnimatedVariable& operator=(const VarType& v) {
if (v == m_Goal)
return *this;
m_Goal = v;
animationBegin = std::chrono::system_clock::now();
m_Begun = m_Value;
onAnimationBegin();
return *this;
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const VarType& v) {
if (v == m_Value)
return;
m_Value = v;
animationBegin = std::chrono::system_clock::now();
m_Begun = m_Value;
onAnimationBegin();
}
// Sets the actual value and goal
void setValueAndWarp(const VarType& v) {
m_Goal = v;
m_bIsBeingAnimated = true;
warp();
}
void warp(bool endCallback = true) override {
if (!m_bIsBeingAnimated)
return;
m_Value = m_Goal;
m_bIsBeingAnimated = false;
if (m_fUpdateCallback)
m_fUpdateCallback(this);
if (endCallback)
onAnimationEnd();
}
private:
VarType m_Value{};
VarType m_Goal{};
VarType m_Begun{};
// owners
friend class CAnimationManager;
friend class CWorkspace;
friend struct SLayerSurface;
friend class CHyprRenderer;
};

View File

@@ -106,6 +106,11 @@ CBox& CBox::expand(const double& value) {
w += value * 2.0;
h += value * 2.0;
if (w <= 0 || h <= 0) {
w = 0;
h = 0;
}
return *this;
}
@@ -116,6 +121,22 @@ CBox& CBox::noNegativeSize() {
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() {
float newW = x + w - std::floor(x);
float newH = y + h - std::floor(y);

View File

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

View File

@@ -722,6 +722,32 @@ int64_t configStringToInt(const std::string& VALUE) {
return std::stoll(VALUE);
}
Vector2D configStringToVector2D(const std::string& VALUE) {
std::istringstream iss(VALUE);
std::string token;
if (!std::getline(iss, token, ' ') && !std::getline(iss, token, ','))
throw std::invalid_argument("Invalid string format");
if (!isNumber(token))
throw std::invalid_argument("Invalid x value");
long long x = std::stoll(token);
if (!std::getline(iss, token))
throw std::invalid_argument("Invalid string format");
if (!isNumber(token))
throw std::invalid_argument("Invalid y value");
long long y = std::stoll(token);
if (std::getline(iss, token))
throw std::invalid_argument("Invalid string format");
return Vector2D(x, y);
}
double normalizeAngleRad(double ang) {
if (ang > M_PI * 2) {
while (ang > M_PI * 2)

View File

@@ -28,6 +28,7 @@ void logSystemInfo();
std::string execAndGet(const char*);
int64_t getPPIDof(int64_t pid);
int64_t configStringToInt(const std::string&);
Vector2D configStringToVector2D(const std::string&);
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
double normalizeAngleRad(double ang);

View File

@@ -1,7 +1,11 @@
#include "Monitor.hpp"
#include "MiscFunctions.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
int ratHandler(void* data) {
g_pHyprRenderer->renderMonitor((CMonitor*)data);
@@ -52,13 +56,18 @@ void CMonitor::onConnect(bool noRule) {
szDescription = output->description ? output->description : "";
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
szDescription.erase(std::remove(szDescription.begin(), szDescription.end(), ','), szDescription.end());
std::erase(szDescription, ',');
// field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix
szShortDescription =
removeBeginEndSpacesTabs(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : ""));
std::erase(szShortDescription, ',');
if (!wlr_backend_is_drm(output->backend))
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
// get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(output->name, output->description ? output->description : "");
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
@@ -136,13 +145,25 @@ void CMonitor::onConnect(bool noRule) {
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
for (const auto& PTOUCHDEV : g_pInputManager->m_lTouchDevices) {
if (matchesStaticSelector(PTOUCHDEV.boundOutput)) {
Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV.name, szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTOUCHDEV.pWlrDevice, output);
}
}
for (const auto& PTABLET : g_pInputManager->m_lTablets) {
if (matchesStaticSelector(PTABLET.boundOutput)) {
Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output);
}
}
if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output);
setupDefaultWS(monitorRule);
@@ -163,13 +184,12 @@ void CMonitor::onConnect(bool noRule) {
//
g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName});
g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)});
EMIT_HOOK_EVENT("monitorAdded", this);
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->setActiveMonitor(this);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
g_pHyprRenderer->arrangeLayersForMonitor(ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
@@ -290,7 +310,7 @@ void CMonitor::onDisconnect(bool destroy) {
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
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) {
int mostHz = 0;
@@ -309,13 +329,11 @@ void CMonitor::onDisconnect(bool destroy) {
}
void CMonitor::addDamage(const pixman_region32_t* rg) {
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("misc:cursor_zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
wlr_damage_ring_add_whole(&damage);
g_pCompositor->scheduleFrameForMonitor(this);
}
if (wlr_damage_ring_add(&damage, rg))
} else if (wlr_damage_ring_add(&damage, rg))
g_pCompositor->scheduleFrameForMonitor(this);
}
@@ -324,7 +342,7 @@ void CMonitor::addDamage(const CRegion* rg) {
}
void CMonitor::addDamage(const CBox* box) {
static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue;
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("misc:cursor_zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
wlr_damage_ring_add_whole(&damage);
g_pCompositor->scheduleFrameForMonitor(this);
@@ -338,6 +356,18 @@ bool CMonitor::isMirror() {
return pMirrorOf != nullptr;
}
bool CMonitor::matchesStaticSelector(const std::string& selector) const {
if (selector.starts_with("desc:")) {
// match by description
const auto DESCRIPTIONSELECTOR = selector.substr(5);
return DESCRIPTIONSELECTOR == szShortDescription || DESCRIPTIONSELECTOR == szDescription;
} else {
// match by selector
return szName == selector;
}
}
int CMonitor::findAvailableDefaultWS() {
for (size_t i = 1; i < INT32_MAX; ++i) {
if (g_pCompositor->getWorkspaceByID(i))
@@ -380,9 +410,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) {
if (newDefaultWorkspaceName == "")
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(ID, newDefaultWorkspaceName)).get();
PNEWWORKSPACE->m_iID = WORKSPACEID;
PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(std::make_unique<CWorkspace>(WORKSPACEID, ID, newDefaultWorkspaceName)).get();
}
activeWorkspace = PNEWWORKSPACE->m_iID;
@@ -417,7 +445,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
pMirrorOf = nullptr;
// set rule
const auto RULE = g_pConfigManager->getMonitorRuleFor(this->szName, this->output->description ? this->output->description : "");
const auto RULE = g_pConfigManager->getMonitorRuleFor(*this);
vecPosition = RULE.offset;
@@ -536,7 +564,7 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
}
if (!noFocus && !g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
CWindow* pWindow = pWorkspace->getLastFocusedWindow();
if (!pWindow) {
@@ -559,6 +587,7 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);
g_pEventManager->postEvent(SHyprIPCEvent{"workspace", pWorkspace->m_szName});
g_pEventManager->postEvent(SHyprIPCEvent{"workspacev2", std::format("{},{}", pWorkspace->m_iID, pWorkspace->m_szName)});
EMIT_HOOK_EVENT("workspace", pWorkspace);
}
@@ -569,10 +598,16 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
g_pConfigManager->ensureVRR(this);
g_pCompositor->updateSuspendedStates();
if (specialWorkspaceID) {
const auto PSPECIALWS = g_pCompositor->getWorkspaceByID(specialWorkspaceID);
if (PSPECIALWS->m_bHasFullscreenWindow)
g_pCompositor->updateFullscreenFadeOnWorkspace(PSPECIALWS);
}
}
void CMonitor::changeWorkspace(const int& id, bool internal) {
changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal);
void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) {
changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus);
}
void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
@@ -594,6 +629,10 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
else
g_pInputManager->refocus();
g_pCompositor->updateFullscreenFadeOnWorkspace(PWORKSPACE);
g_pConfigManager->ensureVRR(this);
g_pCompositor->updateSuspendedStates();
return;
@@ -611,6 +650,10 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
PMONITORWORKSPACEOWNER->specialWorkspaceID = 0;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID);
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMONITORWORKSPACEOWNER->szName});
const auto PACTIVEWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITORWORKSPACEOWNER->activeWorkspace);
g_pCompositor->updateFullscreenFadeOnWorkspace(PACTIVEWORKSPACE);
animate = false;
}
@@ -624,16 +667,17 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
w->m_iMonitorID = ID;
w->updateSurfaceScaleTransformDetails();
w->setAnimationsToMove();
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 it's floating and the middle isnt on the current mon, move it to the center
const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE);
Vector2D pos = w->m_vRealPosition.goalv();
Vector2D pos = w->m_vRealPosition.goal();
if (!VECINRECT(MIDDLE, PMONFROMMIDDLE->vecPosition.x, PMONFROMMIDDLE->vecPosition.y, PMONFROMMIDDLE->vecPosition.x + PMONFROMMIDDLE->vecSize.x,
PMONFROMMIDDLE->vecPosition.y + PMONFROMMIDDLE->vecSize.y)) {
// not on any monitor, center
pos = middle() / 2.f - w->m_vRealSize.goalv() / 2.f;
pos = middle() / 2.f - w->m_vRealSize.goal() / 2.f;
} else
pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition;
@@ -654,6 +698,10 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
g_pHyprRenderer->damageMonitor(this);
g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace);
g_pConfigManager->ensureVRR(this);
g_pCompositor->updateSuspendedStates();
}

View File

@@ -64,6 +64,7 @@ class CMonitor {
std::string szName = "";
std::string szDescription = "";
std::string szShortDescription = "";
Vector2D vecReservedTopLeft = Vector2D(0, 0);
Vector2D vecReservedBottomRight = Vector2D(0, 0);
@@ -84,6 +85,7 @@ class CMonitor {
bool gammaChanged = false;
float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0};
std::optional<Vector2D> forceSize;
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
@@ -105,8 +107,6 @@ class CMonitor {
CMonitor* pMirrorOf = nullptr;
std::vector<CMonitor*> mirrors;
CRegion lastFrameDamage; // stores last frame damage
// for tearing
CWindow* solitaryClient = nullptr;
@@ -140,9 +140,10 @@ class CMonitor {
void addDamage(const CBox* box);
void setMirror(const std::string&);
bool isMirror();
bool matchesStaticSelector(const std::string& selector) const;
float getDefaultScale();
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void changeWorkspace(const int& id, bool internal = false);
void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false);
void setSpecialWorkspace(CWorkspace* const pWorkspace);
void setSpecialWorkspace(const int& id);
void moveTo(const Vector2D& pos);

View File

@@ -112,6 +112,11 @@ CRegion& CRegion::scale(float scale) {
return *this;
}
CRegion& CRegion::scale(const Vector2D& scale) {
wlr_region_scale_xy(&m_rRegion, &m_rRegion, scale.x, scale.y);
return *this;
}
std::vector<pixman_box32_t> CRegion::getRects() const {
std::vector<pixman_box32_t> result;

View File

@@ -49,6 +49,7 @@ class CRegion {
CRegion& invert(pixman_box32_t* box);
CRegion& invert(const CBox& box);
CRegion& scale(float scale);
CRegion& scale(const Vector2D& scale);
CBox getExtents();
bool containsPoint(const Vector2D& vec) const;
bool empty() const;
@@ -57,6 +58,7 @@ class CRegion {
std::vector<pixman_box32_t> getRects() const;
//
pixman_region32_t* pixman() {
return &m_rRegion;
}

View File

@@ -75,6 +75,8 @@ inline const std::vector<std::string> SPLASHES = {
"Join the discord server!",
"Thanks ThatOneCalculator!",
"The AUR packages always work, except for the times they don't.",
"Funny animation compositor woo"
"Funny animation compositor woo",
//
"2 years!"
// clang-format on
};

View File

@@ -1,312 +0,0 @@
#include "SubsurfaceTree.hpp"
#include "../events/Events.hpp"
#include "../Compositor.hpp"
void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
if (!node->pSurface || !node->pSurface->exists())
return;
*lx += node->pSurface->wlr()->current.dx;
*ly += node->pSurface->wlr()->current.dy;
if (node->offsetfn) {
// This is the root node
RASSERT(!node->pSubsurface, "Node had no subsurface!");
node->offsetfn(node->globalOffsetData, lx, ly);
} else {
RASSERT(node->pSubsurface, "Node had no subsurface!");
*lx += node->pSubsurface->pSubsurface->current.x;
*ly += node->pSubsurface->pSubsurface->current.y;
addSurfaceGlobalOffset(node->pParent, lx, ly);
}
}
SSurfaceTreeNode* createTree(wlr_surface* pSurface, CWindow* pWindow) {
const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.emplace_back();
if (pSurface->data)
PNODE->pSurface = (CWLSurface*)pSurface->data;
else {
PNODE->pInternalSurface = pSurface;
PNODE->pSurface = &PNODE->pInternalSurface;
}
PNODE->pWindowOwner = pWindow;
PNODE->hyprListener_newSubsurface.initCallback(&pSurface->events.new_subsurface, &Events::listener_newSubsurfaceNode, PNODE, "SurfaceTreeNode");
PNODE->hyprListener_commit.initCallback(&pSurface->events.commit, &Events::listener_commitSubsurface, PNODE, "SurfaceTreeNode");
PNODE->hyprListener_destroy.initCallback(&pSurface->events.destroy, &Events::listener_destroySubsurfaceNode, PNODE, "SurfaceTreeNode");
wlr_subsurface* wlrSubsurface;
wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_below, current.link) {
Events::listener_newSubsurfaceNode(PNODE, wlrSubsurface);
}
wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_above, current.link) {
Events::listener_newSubsurfaceNode(PNODE, wlrSubsurface);
}
return PNODE;
}
SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* pSubsurface, wlr_surface* surface, CWindow* pWindow) {
const auto PNODE = createTree(surface, pWindow);
PNODE->pParent = pParent;
PNODE->pSubsurface = pSubsurface;
Debug::log(LOG, "Creating a subsurface Node! {}", pWindow);
return PNODE;
}
SSurfaceTreeNode* SubsurfaceTree::createTreeRoot(wlr_surface* pSurface, applyGlobalOffsetFn fn, void* data, CWindow* pWindow) {
const auto PNODE = createTree(pSurface, pWindow);
Debug::log(LOG, "Creating a surfaceTree Root! {}", pWindow);
PNODE->offsetfn = fn;
PNODE->globalOffsetData = data;
return PNODE;
}
void destroySubsurface(SSubsurface* pSubsurface);
void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
bool exists = false;
for (auto& n : surfaceTreeNodes) {
if (&n == pNode) {
exists = true;
break;
}
}
if (!exists) {
Debug::log(ERR, "Tried to remove a SurfaceTreeNode that doesn't exist?? (Node {:x})", (uintptr_t)pNode);
return;
}
for (auto& c : pNode->childSubsurfaces)
destroySubsurface(&c);
pNode->childSubsurfaces.clear();
pNode->hyprListener_commit.removeCallback();
pNode->hyprListener_destroy.removeCallback();
pNode->hyprListener_newSubsurface.removeCallback();
// damage
if (pNode->pSurface && pNode->pSurface->exists()) {
CBox extents = {};
wlr_surface_get_extends(pNode->pSurface->wlr(), extents.pWlr());
extents.applyFromWlr();
int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly);
extents.x += lx;
extents.y += ly;
g_pHyprRenderer->damageBox(&extents);
}
// remove references to this node
for (auto& tn : surfaceTreeNodes) {
for (auto& cs : tn.childSubsurfaces) {
if (cs.pChild == pNode)
cs.pChild = nullptr;
}
}
surfaceTreeNodes.remove(*pNode);
Debug::log(LOG, "SurfaceTree Node removed");
}
void destroySubsurface(SSubsurface* pSubsurface) {
if (pSubsurface->pChild) {
SubsurfaceTree::destroySurfaceTree(pSubsurface->pChild);
pSubsurface->pChild = nullptr;
}
pSubsurface->hyprListener_destroy.removeCallback();
pSubsurface->hyprListener_map.removeCallback();
pSubsurface->hyprListener_unmap.removeCallback();
}
//
// Subsurface listeners
//
void Events::listener_newSubsurfaceNode(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
const auto PSUBSURFACE = (wlr_subsurface*)data;
const auto PNEWSUBSURFACE = &pNode->childSubsurfaces.emplace_back();
Debug::log(LOG, "Added a new subsurface {:x}", (uintptr_t)PSUBSURFACE);
PNEWSUBSURFACE->pSubsurface = PSUBSURFACE;
PNEWSUBSURFACE->pParent = pNode;
PNEWSUBSURFACE->hyprListener_map.initCallback(&PSUBSURFACE->surface->events.map, &Events::listener_mapSubsurface, PNEWSUBSURFACE, "Subsurface");
PNEWSUBSURFACE->hyprListener_unmap.initCallback(&PSUBSURFACE->surface->events.unmap, &Events::listener_unmapSubsurface, PNEWSUBSURFACE, "Subsurface");
PNEWSUBSURFACE->hyprListener_destroy.initCallback(&PSUBSURFACE->events.destroy, &Events::listener_destroySubsurface, PNEWSUBSURFACE, "Subsurface");
PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner;
if (PSUBSURFACE->surface->mapped)
listener_mapSubsurface(PNEWSUBSURFACE, nullptr);
wlr_subsurface* existingWlrSubsurface;
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) {
listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
}
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_above, current.link) {
listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
}
}
void Events::listener_mapSubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
if (subsurface->pChild)
return;
Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface);
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
if (subsurface->pWindowOwner)
subsurface->pWindowOwner->updateSurfaceScaleTransformDetails();
}
void Events::listener_unmapSubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
Debug::log(LOG, "Subsurface {:x} unmapped", (uintptr_t)subsurface);
if (subsurface->pSubsurface->surface == g_pCompositor->m_pLastFocus)
g_pInputManager->releaseAllMouseButtons();
if (subsurface->pChild) {
const auto PNODE = subsurface->pChild;
const auto IT =
std::find_if(SubsurfaceTree::surfaceTreeNodes.begin(), SubsurfaceTree::surfaceTreeNodes.end(), [&](const SSurfaceTreeNode& other) { return &other == PNODE; });
if (IT != SubsurfaceTree::surfaceTreeNodes.end()) {
if (PNODE->pSurface && PNODE->pSurface->exists()) {
int lx = 0, ly = 0;
addSurfaceGlobalOffset(PNODE, &lx, &ly);
CBox extents = {lx, ly, 0, 0};
extents.width = PNODE->pSurface->wlr()->current.width;
extents.height = PNODE->pSurface->wlr()->current.height;
g_pHyprRenderer->damageBox(&extents);
}
// SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
// subsurface->pChild = nullptr;
}
}
g_pInputManager->simulateMouseMovement(); // to focus and return back to an appropriate surface
}
void Events::listener_commitSubsurface(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
// no damaging if it's not visible
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Refusing to commit damage from {} because it's invisible.", pNode->pWindowOwner);
return;
}
int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly);
const double SCALE = pNode->pWindowOwner && pNode->pWindowOwner->m_bIsX11 ? 1.0 / pNode->pWindowOwner->m_fX11SurfaceScaledBy : 1.0;
// I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox)
// What this does is that basically, if the pNode is a child of some other node, on commit,
// it will also damage (check & damage if needed) all its siblings.
if (pNode->pParent)
for (auto& cs : pNode->pParent->childSubsurfaces) {
const auto NODECOORDS = pNode->pSubsurface ? Vector2D(pNode->pSubsurface->pSubsurface->current.x, pNode->pSubsurface->pSubsurface->current.y) : Vector2D();
if (&cs != pNode->pSubsurface && cs.pSubsurface) {
g_pHyprRenderer->damageSurface(cs.pSubsurface->surface, lx - NODECOORDS.x + cs.pSubsurface->current.x, ly - NODECOORDS.y + cs.pSubsurface->current.y, SCALE);
}
}
if (pNode->pSurface && pNode->pSurface->exists()) {
g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE);
if (pNode->lastSize != Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} && pNode->pWindowOwner)
g_pHyprRenderer->damageWindow(pNode->pWindowOwner);
}
if (pNode->pWindowOwner) {
if (pNode->pWindowOwner->m_bIsX11)
pNode->pWindowOwner->m_vReportedSize = pNode->pWindowOwner->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged.
// tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
CRegion damageBox{&pNode->pSurface->wlr()->buffer_damage};
if (!damageBox.empty()) {
if (PMONITOR->tearingState.busy) {
PMONITOR->tearingState.frameScheduledWhileBusy = true;
} else {
PMONITOR->tearingState.nextRenderTorn = true;
g_pHyprRenderer->renderMonitor(PMONITOR);
}
}
}
}
pNode->lastSize = pNode->pSurface->exists() ? Vector2D{pNode->pSurface->wlr()->current.width, pNode->pSurface->wlr()->current.height} : Vector2D{};
}
void Events::listener_destroySubsurface(void* owner, void* data) {
SSubsurface* subsurface = (SSubsurface*)owner;
if (subsurface->pChild) {
SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
}
Debug::log(LOG, "Subsurface {:x} destroyed", (uintptr_t)subsurface);
subsurface->hyprListener_destroy.removeCallback();
subsurface->hyprListener_map.removeCallback();
subsurface->hyprListener_unmap.removeCallback();
subsurface->pParent->childSubsurfaces.remove(*subsurface);
}
void Events::listener_destroySubsurfaceNode(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
Debug::log(LOG, "Subsurface Node {:x} destroyed", (uintptr_t)pNode);
for (auto& c : pNode->childSubsurfaces)
destroySubsurface(&c);
pNode->hyprListener_commit.removeCallback();
pNode->hyprListener_newSubsurface.removeCallback();
pNode->hyprListener_destroy.removeCallback();
SubsurfaceTree::surfaceTreeNodes.remove(*pNode);
}

View File

@@ -1,60 +0,0 @@
#pragma once
#include "../defines.hpp"
#include <list>
#include "WLSurface.hpp"
struct SSubsurface;
class CWindow;
typedef void (*applyGlobalOffsetFn)(void*, int*, int*);
struct SSurfaceTreeNode {
CWLSurface* pSurface = nullptr; // actual surface
CWLSurface pInternalSurface; // not present for head nodes to not dupe wlr_surface ownership
DYNLISTENER(newSubsurface);
DYNLISTENER(commit);
DYNLISTENER(destroy);
SSurfaceTreeNode* pParent = nullptr;
SSubsurface* pSubsurface = nullptr;
std::list<SSubsurface> childSubsurfaces;
applyGlobalOffsetFn offsetfn;
void* globalOffsetData;
CWindow* pWindowOwner = nullptr;
Vector2D lastSize;
//
bool operator==(const SSurfaceTreeNode& rhs) const {
return pSurface == rhs.pSurface;
}
};
struct SSubsurface {
wlr_subsurface* pSubsurface = nullptr;
SSurfaceTreeNode* pParent = nullptr;
SSurfaceTreeNode* pChild = nullptr;
DYNLISTENER(map);
DYNLISTENER(unmap);
DYNLISTENER(destroy);
CWindow* pWindowOwner = nullptr;
//
bool operator==(const SSubsurface& rhs) const {
return pSubsurface == rhs.pSubsurface;
}
};
namespace SubsurfaceTree {
SSurfaceTreeNode* createTreeRoot(wlr_surface*, applyGlobalOffsetFn, void*, CWindow* pWindow = nullptr);
void destroySurfaceTree(SSurfaceTreeNode*);
inline std::list<SSurfaceTreeNode> surfaceTreeNodes;
};

View File

@@ -12,6 +12,11 @@ Vector2D::Vector2D() {
y = 0;
}
Vector2D::Vector2D(const Hyprlang::VEC2& ref) {
x = ref.x;
y = ref.y;
}
Vector2D::~Vector2D() {}
double Vector2D::normalize() {

View File

@@ -3,12 +3,14 @@
#include <cmath>
#include <format>
#include "../macros.hpp"
#include <hyprlang.hpp>
class Vector2D {
public:
Vector2D(double, double);
Vector2D();
~Vector2D();
Vector2D(const Hyprlang::VEC2&);
double x = 0;
double y = 0;
@@ -88,7 +90,7 @@ class Vector2D {
double distance(const Vector2D& other) const;
double size() const;
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const;
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D{-1, -1}) const;
Vector2D floor() const;
Vector2D round() const;

View File

@@ -3,9 +3,14 @@
#include "../Compositor.hpp"
SLayerSurface::SLayerSurface() {
alpha.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), nullptr, AVARDAMAGE_ENTIRE);
alpha.m_pLayer = this;
alpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeLayers"), this, AVARDAMAGE_ENTIRE);
realPosition.create(g_pConfigManager->getAnimationPropertyConfig("layers"), this, AVARDAMAGE_ENTIRE);
realSize.create(g_pConfigManager->getAnimationPropertyConfig("layers"), this, AVARDAMAGE_ENTIRE);
alpha.registerVar();
realPosition.registerVar();
realSize.registerVar();
alpha.setValueAndWarp(0.f);
}
SLayerSurface::~SLayerSurface() {
@@ -22,12 +27,15 @@ void SLayerSurface::applyRules() {
ignoreAlpha = false;
ignoreAlphaValue = 0.f;
xray = -1;
animationStyle.reset();
for (auto& rule : g_pConfigManager->getMatchingRules(this)) {
if (rule.rule == "noanim")
noAnimations = true;
else if (rule.rule == "blur")
forceBlur = true;
else if (rule.rule == "blurpopups")
forceBlurPopups = true;
else if (rule.rule.starts_with("ignorealpha") || rule.rule.starts_with("ignorezero")) {
const auto FIRST_SPACE_POS = rule.rule.find_first_of(' ');
std::string alphaValue = "";
@@ -44,82 +52,221 @@ void SLayerSurface::applyRules() {
try {
xray = configStringToInt(vars[1]);
} catch (...) {}
} else if (rule.rule.starts_with("animation")) {
CVarList vars{rule.rule, 2, 's'};
animationStyle = vars[1];
}
}
}
CRegion SConstraint::getLogicCoordsRegion() {
CRegion result;
void SLayerSurface::startAnimation(bool in, bool instant) {
const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle);
if (!constraint)
return result;
if (ANIMSTYLE.starts_with("slide")) {
// get closest edge
const auto MIDDLE = geometry.middle();
const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface);
const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE);
if (!PWINDOWOWNER)
return result;
int force = -1;
result.add(&constraint->region); // surface-local coords
if (!PWINDOWOWNER->m_bIsX11) {
result.translate(PWINDOWOWNER->m_vRealPosition.goalv());
return result;
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 auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() :
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y});
const std::array<Vector2D, 4> edgePoints = {
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y},
PMONITOR->vecPosition + Vector2D{0, PMONITOR->vecSize.y},
PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2},
};
const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ? g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) : g_pCompositor->getMonitorFromVector(COORDS);
float closest = std::numeric_limits<float>::max();
int leader = force;
if (leader == -1) {
for (size_t i = 0; i < 4; ++i) {
float dist = MIDDLE.distance(edgePoints[i]);
if (dist < closest) {
leader = i;
closest = dist;
}
}
}
if (!PMONITOR)
return CRegion{};
realSize.setValueAndWarp(geometry.size());
alpha.setValueAndWarp(in ? 0.f : 1.f);
alpha = in ? 1.f : 0.f;
result.scale(PMONITOR->xwaylandScale);
Vector2D prePos;
result.translate(COORDS);
switch (leader) {
case 0:
// TOP
prePos = {geometry.x, PMONITOR->vecPosition.y - geometry.h};
break;
case 1:
// BOTTOM
prePos = {geometry.x, PMONITOR->vecPosition.y + PMONITOR->vecSize.y};
break;
case 2:
// LEFT
prePos = {PMONITOR->vecPosition.x - geometry.w, geometry.y};
break;
case 3:
// RIGHT
prePos = {PMONITOR->vecPosition.x + PMONITOR->vecSize.x, geometry.y};
break;
default: UNREACHABLE();
}
return result;
if (in) {
realPosition.setValueAndWarp(prePos);
realPosition = geometry.pos();
} else {
realPosition.setValueAndWarp(geometry.pos());
realPosition = prePos;
}
} else if (ANIMSTYLE.starts_with("popin")) {
float minPerc = 0.f;
if (ANIMSTYLE.find("%") != std::string::npos) {
try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) {
; // oops
}
}
minPerc *= 0.01;
const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5});
const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f;
alpha.setValueAndWarp(in ? 0.f : 1.f);
alpha = in ? 1.f : 0.f;
if (in) {
realSize.setValueAndWarp(GOALSIZE);
realPosition.setValueAndWarp(GOALPOS);
realSize = geometry.size();
realPosition = geometry.pos();
} else {
realSize.setValueAndWarp(geometry.size());
realPosition.setValueAndWarp(geometry.pos());
realSize = GOALSIZE;
realPosition = GOALPOS;
}
} else {
// fade
realPosition.setValueAndWarp(geometry.pos());
realSize.setValueAndWarp(geometry.size());
alpha = in ? 1.f : 0.f;
}
if (!in)
fadingOut = true;
}
Vector2D SConstraint::getLogicConstraintPos() {
if (!constraint)
return {};
bool SLayerSurface::isFadedOut() {
if (!fadingOut)
return false;
const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface);
if (!PWINDOWOWNER)
return {};
if (!PWINDOWOWNER->m_bIsX11)
return PWINDOWOWNER->m_vRealPosition.goalv();
const auto COORDS = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealPosition.goalv() :
g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y});
return COORDS;
return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated();
}
Vector2D SConstraint::getLogicConstraintSize() {
if (!constraint)
return {};
int SLayerSurface::popupsCount() {
if (!layerSurface || !mapped || fadingOut)
return 0;
const auto PWINDOWOWNER = g_pCompositor->getWindowFromSurface(constraint->surface);
if (!PWINDOWOWNER)
return {};
if (!PWINDOWOWNER->m_bIsX11)
return PWINDOWOWNER->m_vRealSize.goalv();
const auto PMONITOR = PWINDOWOWNER->m_bIsMapped ?
g_pCompositor->getMonitorFromID(PWINDOWOWNER->m_iMonitorID) :
g_pCompositor->getMonitorFromVector(g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOWOWNER->m_uSurface.xwayland->x, PWINDOWOWNER->m_uSurface.xwayland->y}));
if (!PMONITOR)
return {};
const auto SIZE = PWINDOWOWNER->m_bIsMapped ? PWINDOWOWNER->m_vRealSize.goalv() :
Vector2D{PWINDOWOWNER->m_uSurface.xwayland->width, PWINDOWOWNER->m_uSurface.xwayland->height} * PMONITOR->xwaylandScale;
return SIZE;
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) {
xkb_state_unref(xkbTranslationState);
if (keymap) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
xkbTranslationState = xkb_state_new(keymap);
return;
}
const auto WLRKB = wlr_keyboard_from_input_device(keyboard);
const auto KEYMAP = WLRKB->keymap;
const auto STATE = WLRKB->xkb_state;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE)) {
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an active index {}", (uintptr_t)this, i);
CVarList keyboardLayouts(currentRules.layout, 0, ',');
CVarList keyboardModels(currentRules.model, 0, ',');
CVarList keyboardVariants(currentRules.variant, 0, ',');
xkb_rule_names rules = {.rules = "", .model = "", .layout = "", .variant = "", .options = ""};
std::string layout, model, variant;
layout = keyboardLayouts[i % keyboardLayouts.size()];
model = keyboardModels[i % keyboardModels.size()];
variant = keyboardVariants[i % keyboardVariants.size()];
rules.layout = layout.c_str();
rules.model = model.c_str();
rules.variant = variant.c_str();
auto KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!KEYMAP) {
Debug::log(ERR, "updateXKBTranslationState: keymap failed 1, fallback without model/variant");
rules.model = "";
rules.variant = "";
KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
if (!KEYMAP) {
Debug::log(ERR, "updateXKBTranslationState: keymap failed 2, fallback to us");
rules.layout = "us";
KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
xkbTranslationState = xkb_state_new(KEYMAP);
xkb_keymap_unref(KEYMAP);
xkb_context_unref(PCONTEXT);
return;
}
}
Debug::log(LOG, "Updating keyboard {:x}'s translation state from an unknown index", (uintptr_t)this);
xkb_rule_names rules = {
.rules = currentRules.rules.c_str(),
.model = currentRules.model.c_str(),
.layout = currentRules.layout.c_str(),
.variant = currentRules.variant.c_str(),
.options = currentRules.options.c_str(),
};
const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkbTranslationState = xkb_state_new(NEWKEYMAP);
xkb_keymap_unref(NEWKEYMAP);
xkb_context_unref(PCONTEXT);
}

View File

@@ -3,10 +3,11 @@
#include "../events/Events.hpp"
#include "../defines.hpp"
#include "wlr-layer-shell-unstable-v1-protocol.h"
#include "../Window.hpp"
#include "SubsurfaceTree.hpp"
#include "../desktop/Window.hpp"
#include "../desktop/Subsurface.hpp"
#include "../desktop/Popup.hpp"
#include "AnimatedVariable.hpp"
#include "WLSurface.hpp"
#include "../desktop/WLSurface.hpp"
#include "Region.hpp"
struct SLayerRule {
@@ -19,6 +20,12 @@ struct SLayerSurface {
~SLayerSurface();
void applyRules();
void startAnimation(bool in, bool instant = false);
bool isFadedOut();
int popupsCount();
CAnimatedVariable<Vector2D> realPosition;
CAnimatedVariable<Vector2D> realSize;
wlr_layer_surface_v1* layerSurface;
wl_list link;
@@ -26,13 +33,14 @@ struct SLayerSurface {
bool keyboardExclusive = false;
CWLSurface surface;
std::list<CWLSurface> popupSurfaces;
// desktop components
std::unique_ptr<CPopup> popupHead;
DYNLISTENER(destroyLayerSurface);
DYNLISTENER(mapLayerSurface);
DYNLISTENER(unmapLayerSurface);
DYNLISTENER(commitLayerSurface);
DYNLISTENER(newPopup);
CBox geometry = {0, 0, 0, 0};
Vector2D position;
@@ -44,17 +52,20 @@ struct SLayerSurface {
std::string szNamespace = "";
CAnimatedVariable alpha;
CAnimatedVariable<float> alpha;
bool fadingOut = false;
bool readyToDelete = false;
bool noProcess = false;
bool noAnimations = false;
bool forceBlur = false;
bool forceBlurPopups = false;
int xray = -1;
bool ignoreAlpha = false;
float ignoreAlphaValue = 0.f;
std::optional<std::string> animationStyle;
// For the list lookup
bool operator==(const SLayerSurface& rhs) const {
return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID;
@@ -128,6 +139,7 @@ struct SKeyboard {
bool enabled = true;
xkb_layout_index_t activeLayout = 0;
xkb_state* xkbTranslationState = nullptr;
std::string name = "";
std::string xkbFilePath = "";
@@ -136,6 +148,9 @@ struct SKeyboard {
int repeatRate = 0;
int repeatDelay = 0;
int numlockOn = -1;
bool resolveBindsBySym = false;
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
// For the list lookup
bool operator==(const SKeyboard& rhs) const {
@@ -146,18 +161,12 @@ struct SKeyboard {
struct SMouse {
wlr_input_device* mouse = nullptr;
wlr_pointer_constraint_v1* currentConstraint = nullptr;
bool constraintActive = false;
CRegion confinedTo;
std::string name = "";
bool virt = false;
bool connected = false; // means connected to the cursor
DYNLISTENER(commitConstraint);
DYNLISTENER(destroyMouse);
bool operator==(const SMouse& b) const {
@@ -165,59 +174,8 @@ struct SMouse {
}
};
struct SConstraint {
SMouse* pMouse = nullptr;
wlr_pointer_constraint_v1* constraint = nullptr;
bool active = false;
bool hintSet = false;
Vector2D positionHint = {-1, -1}; // the position hint, but will use cursorPosOnActivate if unset
Vector2D cursorPosOnActivate = {-1, -1};
DYNLISTENER(setConstraintRegion);
DYNLISTENER(destroyConstraint);
CRegion getLogicCoordsRegion();
Vector2D getLogicConstraintPos();
Vector2D getLogicConstraintSize();
//
bool operator==(const SConstraint& b) const {
return constraint == b.constraint;
}
};
class CMonitor;
struct SXDGPopup {
CWindow* parentWindow = nullptr;
SLayerSurface* parentLS = nullptr;
SXDGPopup* parentPopup = nullptr;
wlr_xdg_popup* popup = nullptr;
CMonitor* monitor = nullptr;
DYNLISTENER(newPopupFromPopupXDG);
DYNLISTENER(destroyPopupXDG);
DYNLISTENER(mapPopupXDG);
DYNLISTENER(unmapPopupXDG);
DYNLISTENER(commitPopupXDG);
DYNLISTENER(repositionPopupXDG);
double lx;
double ly;
Vector2D lastPos = {};
bool repositionRequested = false;
SSurfaceTreeNode* pSurfaceTree = nullptr;
// For the list lookup
bool operator==(const SXDGPopup& rhs) const {
return popup == rhs.popup;
}
};
struct SSeat {
wlr_seat* seat = nullptr;
wl_client* exclusiveClient = nullptr;
@@ -259,6 +217,10 @@ struct STablet {
std::string name = "";
std::string boundOutput = "";
CBox activeArea;
//
bool operator==(const STablet& b) const {
return wlrDevice == b.wlrDevice;
@@ -325,26 +287,11 @@ struct SSwipeGesture {
int initialDirection = 0;
float avgSpeed = 0;
int speedPoints = 0;
int touch_id = 0;
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 {
wlr_input_method_keyboard_grab_v2* pWlrKbGrab = nullptr;
@@ -353,26 +300,6 @@ struct SIMEKbGrab {
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 {
wlr_input_device* pWlrDevice = nullptr;
@@ -406,7 +333,17 @@ struct STearingController {
DYNLISTENER(set);
DYNLISTENER(destroy);
bool operator==(const STearingController& other) {
bool operator==(const STearingController& other) const {
return pWlrHint == other.pWlrHint;
}
};
struct SShortcutInhibitor {
wlr_keyboard_shortcuts_inhibitor_v1* pWlrInhibitor = nullptr;
DYNLISTENER(destroy);
bool operator==(const SShortcutInhibitor& other) const {
return pWlrInhibitor == other.pWlrInhibitor;
}
};

View File

@@ -1,87 +0,0 @@
#include "WLSurface.hpp"
#include "../Compositor.hpp"
CWLSurface::CWLSurface(wlr_surface* pSurface) {
m_pWLRSurface = pSurface;
init();
}
void CWLSurface::assign(wlr_surface* pSurface) {
m_pWLRSurface = pSurface;
init();
}
void CWLSurface::unassign() {
destroy();
}
CWLSurface::~CWLSurface() {
destroy();
}
bool CWLSurface::exists() const {
return m_pWLRSurface;
}
wlr_surface* CWLSurface::wlr() const {
return m_pWLRSurface;
}
bool CWLSurface::small() const {
if (!m_pOwner || !exists())
return false;
return m_pOwner->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || m_pOwner->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1;
}
Vector2D CWLSurface::correctSmallVec() const {
if (!m_pOwner || !exists() || !small() || m_bFillIgnoreSmall)
return {};
const auto SIZE = getViewporterCorrectedSize();
return Vector2D{(m_pOwner->m_vReportedSize.x - SIZE.x) / 2, (m_pOwner->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) *
(m_pOwner->m_vRealSize.vec() / m_pOwner->m_vReportedSize);
}
Vector2D CWLSurface::getViewporterCorrectedSize() const {
if (!exists())
return {};
return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} :
Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
}
void CWLSurface::destroy() {
if (!m_pWLRSurface)
return;
hyprListener_destroy.removeCallback();
m_pWLRSurface->data = nullptr;
m_pOwner = nullptr;
if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
g_pCompositor->m_pLastFocus = nullptr;
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_pWLRSurface = nullptr;
Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
}
void CWLSurface::init() {
if (!m_pWLRSurface)
return;
RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!");
m_pWLRSurface->data = this;
hyprListener_destroy.initCallback(
&m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
}

View File

@@ -1,6 +1,7 @@
#include "Watchdog.hpp"
#include <signal.h>
#include "config/ConfigManager.hpp"
#include "../config/ConfigValue.hpp"
CWatchdog::~CWatchdog() {
m_bExitThread = true;
@@ -13,7 +14,7 @@ CWatchdog::CWatchdog() {
m_iMainThreadPID = pthread_self();
m_pWatchdog = std::make_unique<std::thread>([this] {
static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
static auto PTIMEOUT = CConfigValue<Hyprlang::INT>("debug:watchdog_timeout");
while (1337) {
std::unique_lock lk(m_mWatchdogMutex);
@@ -37,7 +38,7 @@ CWatchdog::CWatchdog() {
}
void CWatchdog::startWatching() {
static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
static auto PTIMEOUT = CConfigValue<Hyprlang::INT>("debug:watchdog_timeout");
if (*PTIMEOUT == 0)
return;

View File

@@ -1,176 +0,0 @@
#include "Workspace.hpp"
#include "../Compositor.hpp"
CWorkspace::CWorkspace(int monitorID, std::string name, bool special) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) {
Debug::log(ERR, "Attempted a creation of CWorkspace with an invalid monitor?");
return;
}
m_iMonitorID = monitorID;
m_szName = name;
m_bIsSpecialWorkspace = special;
m_vRenderOffset.m_pWorkspace = this;
m_vRenderOffset.create(AVARTYPE_VECTOR, special ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"),
nullptr, 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_vRenderOffset.registerVar();
m_fAlpha.registerVar();
g_pEventManager->postEvent({"createworkspace", m_szName});
EMIT_HOOK_EVENT("createWorkspace", this);
}
CWorkspace::~CWorkspace() {
m_vRenderOffset.unregister();
Debug::log(LOG, "Destroying workspace ID {}", m_iID);
g_pEventManager->postEvent({"destroyworkspace", m_szName});
EMIT_HOOK_EVENT("destroyWorkspace", this);
}
void CWorkspace::startAnim(bool in, bool left, bool instant) {
const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle;
const auto PWORKSPACEGAP = &g_pConfigManager->getConfigValuePtr("general:gaps_workspaces")->intValue;
if (ANIMSTYLE.starts_with("slidefade")) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
float movePerc = 100.f;
if (ANIMSTYLE.find("%") != std::string::npos) {
try {
auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1);
movePerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); }
}
m_fAlpha.setValueAndWarp(1.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
if (ANIMSTYLE.starts_with("slidefadevert")) {
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f)));
m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0);
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
m_vRenderOffset = Vector2D(0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f));
}
} else {
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0));
m_fAlpha = 1.f;
m_vRenderOffset = Vector2D(0, 0);
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0);
}
}
} else if (ANIMSTYLE == "fade") {
m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade.
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_fAlpha = 1.f;
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
}
} else if (ANIMSTYLE == "slidevert") {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? YDISTANCE : -YDISTANCE));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(0, left ? -YDISTANCE : YDISTANCE);
}
} else {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP;
m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0);
}
}
if (m_bIsSpecialWorkspace) {
// required for open/close animations
if (in) {
m_fAlpha.setValueAndWarp(0.f);
m_fAlpha = 1.f;
} else {
m_fAlpha.setValueAndWarp(1.f);
m_fAlpha = 0.f;
}
}
if (instant) {
m_vRenderOffset.warp();
m_fAlpha.warp();
}
}
void CWorkspace::setActive(bool on) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
void CWorkspace::moveToMonitor(const int& id) {
; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40
}
CWindow* CWorkspace::getLastFocusedWindow() {
if (!g_pCompositor->windowValidMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow->m_iWorkspaceID != m_iID)
return nullptr;
return m_pLastFocusedWindow;
}
void CWorkspace::rememberPrevWorkspace(const CWorkspace* prev) {
if (!prev) {
m_sPrevWorkspace.iID = -1;
m_sPrevWorkspace.name = "";
return;
}
if (prev->m_iID == m_iID) {
Debug::log(LOG, "Tried to set prev workspace to the same as current one");
return;
}
m_sPrevWorkspace.iID = prev->m_iID;
m_sPrevWorkspace.name = prev->m_szName;
}
std::string CWorkspace::getConfigName() {
if (m_bIsSpecialWorkspace) {
return "special:" + m_szName;
}
if (m_iID > 0)
return std::to_string(m_iID);
return "name:" + m_szName;
}

View File

@@ -168,3 +168,5 @@ inline wlr_xwayland_surface* wlr_xwayland_surface_try_from_wlr_surface(wlr_surfa
inline bool wlr_xwayland_or_surface_wants_focus(const wlr_xwayland_surface*) {
return false;
}
inline void wlr_xwayland_set_cursor(wlr_xwayland* wlr_xwayland, uint8_t* pixels, uint32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) {}

View File

@@ -1,8 +1,9 @@
#include "HyprError.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
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();
g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) {
@@ -58,6 +59,10 @@ void CHyprError::createQueued() {
cairo_restore(CAIRO);
const auto LINECOUNT = 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;
@@ -66,7 +71,7 @@ void CHyprError::createQueued() {
const double X = PAD;
const double Y = PAD;
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;
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);
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'));
if (const auto NEWLPOS = m_szQueued.find('\n'); NEWLPOS != std::string::npos)
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_show_text(CAIRO, current.c_str());
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);
@@ -139,7 +152,7 @@ void CHyprError::draw() {
if (m_bQueuedDestroy) {
if (!m_fFadeOpacity.isBeingAnimated()) {
if (m_fFadeOpacity.fl() == 0.f) {
if (m_fFadeOpacity.value() == 0.f) {
m_bQueuedDestroy = false;
m_tTexture.destroyTexture();
m_bIsCreated = false;
@@ -164,7 +177,7 @@ void CHyprError::draw() {
m_bMonitorChanged = false;
g_pHyprOpenGL->renderTexture(m_tTexture, &monbox, m_fFadeOpacity.fl(), 0);
g_pHyprOpenGL->renderTexture(m_tTexture, &monbox, m_fFadeOpacity.value(), 0);
}
void CHyprError::destroy() {

View File

@@ -22,7 +22,7 @@ class CHyprError {
bool m_bQueuedDestroy = false;
bool m_bIsCreated = false;
CTexture m_tTexture;
CAnimatedVariable m_fFadeOpacity;
CAnimatedVariable<float> m_fFadeOpacity;
CBox m_bDamageBox = {0, 0, 0, 0};
bool m_bMonitorChanged = false;

View File

@@ -63,7 +63,6 @@ extern "C" {
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_xdg_activation_v1.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_output_v1.h>
@@ -76,6 +75,7 @@ extern "C" {
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include <wlr/util/edges.h>
#include <wlr/types/wlr_tablet_pad.h>
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/types/wlr_tablet_v2.h>

View File

@@ -1,16 +1,16 @@
#include "DwindleLayout.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) {
if (children[0]) {
static auto* const PSMARTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:smart_split")->intValue;
static auto* const PPRESERVESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:preserve_split")->intValue;
static auto* const PFLMULT = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
static auto PSMARTSPLIT = CConfigValue<Hyprlang::INT>("dwindle:smart_split");
static auto PPRESERVESPLIT = CConfigValue<Hyprlang::INT>("dwindle:preserve_split");
static auto PFLMULT = CConfigValue<Hyprlang::FLOAT>("dwindle:split_width_multiplier");
if (*PPRESERVESPLIT == 0 && *PSMARTSPLIT == 0) {
if (*PPRESERVESPLIT == 0 && *PSMARTSPLIT == 0)
splitTop = box.h * *PFLMULT > box.w;
}
if (verticalOverride == true)
splitTop = true;
@@ -128,24 +128,32 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
const auto PWINDOW = pNode->pWindow;
// get specific gaps and rules for this workspace,
// if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID));
const auto WORKSPACERULES = g_pConfigManager->getWorkspaceRulesFor(g_pCompositor->getWorkspaceByID(pNode->workspaceID));
if (!g_pCompositor->windowExists(PWINDOW)) {
Debug::log(ERR, "Node {} holding invalid {}!!", pNode, PWINDOW);
onWindowRemovedTiling(PWINDOW);
return;
}
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return;
PWINDOW->updateSpecialRenderData();
static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
static auto* const PGAPSOUT = &g_pConfigManager->getConfigValuePtr("general:gaps_out")->intValue;
static auto* const PNOGAPSWHENONLY = &g_pConfigManager->getConfigValuePtr("dwindle:no_gaps_when_only")->intValue;
static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("dwindle:no_gaps_when_only");
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
auto* const PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData();
auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData();
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
if (!g_pCompositor->windowExists(PWINDOW) || !PWINDOW->m_bIsMapped) {
Debug::log(ERR, "Node {} holding invalid {}!!", pNode, PWINDOW);
onWindowRemovedTiling(PWINDOW);
return;
auto gapsIn = *PGAPSIN;
auto gapsOut = *PGAPSOUT;
for (auto& wsRule : WORKSPACERULES) {
if (wsRule.gapsIn.has_value())
gapsIn = wsRule.gapsIn.value();
if (wsRule.gapsOut.has_value())
gapsOut = wsRule.gapsOut.value();
}
CBox nodeBox = pNode->box;
@@ -159,10 +167,17 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
if (*PNOGAPSWHENONLY && !g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) &&
(NODESONWORKSPACE == 1 || (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.decorate = WORKSPACERULE.decorate.value_or(true);
PWINDOW->m_sSpecialRenderData.rounding = false;
PWINDOW->m_sSpecialRenderData.shadow = false;
PWINDOW->m_sSpecialRenderData.border = (*PNOGAPSWHENONLY == 2);
PWINDOW->m_sSpecialRenderData.decorate = true;
for (auto& wsRule : WORKSPACERULES) {
if (wsRule.border.has_value())
PWINDOW->m_sSpecialRenderData.border = wsRule.border.value();
if (wsRule.decorate.has_value())
PWINDOW->m_sSpecialRenderData.decorate = wsRule.decorate.value();
}
PWINDOW->updateWindowDecos();
@@ -171,7 +186,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft;
PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
return;
}
@@ -179,9 +194,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
auto calcPos = PWINDOW->m_vPosition;
auto calcSize = PWINDOW->m_vSize;
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut : gapsIn, DISPLAYTOP ? gapsOut : gapsIn);
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut.left : gapsIn.left, DISPLAYTOP ? gapsOut.top : gapsIn.top);
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? gapsOut : gapsIn, DISPLAYBOTTOM ? gapsOut : gapsIn);
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? gapsOut.right : gapsIn.right, DISPLAYBOTTOM ? gapsOut.bottom : gapsIn.bottom);
calcPos = calcPos + OFFSETTOPLEFT;
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
@@ -214,9 +229,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
calcPos = calcPos + RESERVED.topLeft;
calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight);
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && !PWINDOW->m_bIsFullscreen) {
// if special, we adjust the coords a bit
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue;
static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("dwindle:special_scale_factor");
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
wb.round(); // avoid rounding mess
@@ -226,10 +241,13 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
} else {
PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos;
CBox wb = {calcPos, calcSize};
wb.round(); // avoid rounding mess
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
PWINDOW->m_vRealSize = wb.size();
PWINDOW->m_vRealPosition = wb.pos();
g_pXWaylandManager->setWindowSize(PWINDOW, wb.size());
}
if (force) {
@@ -253,8 +271,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
static auto* const PUSEACTIVE = &g_pConfigManager->getConfigValuePtr("dwindle:use_active_for_splits")->intValue;
static auto* const PDEFAULTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:default_split_ratio")->floatValue;
static auto PUSEACTIVE = CConfigValue<Hyprlang::INT>("dwindle:use_active_for_splits");
static auto PDEFAULTSPLIT = CConfigValue<Hyprlang::FLOAT>("dwindle:default_split_ratio");
if (direction != DIRECTION_DEFAULT && overrideDirection == DIRECTION_DEFAULT)
overrideDirection = direction;
@@ -339,7 +357,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
&& pWindow->canBeGroupedInto(OPENINGON->pWindow) && !m_vOverrideFocalPoint) { // we are not moving window
m_lDwindleNodesData.remove(*PNODE);
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
@@ -365,15 +383,15 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
NEWPARENT->isNode = true; // it is a node
NEWPARENT->splitRatio = std::clamp(*PDEFAULTSPLIT, 0.1f, 1.9f);
const auto PWIDTHMULTIPLIER = &g_pConfigManager->getConfigValuePtr("dwindle:split_width_multiplier")->floatValue;
static auto PWIDTHMULTIPLIER = CConfigValue<Hyprlang::FLOAT>("dwindle:split_width_multiplier");
// if cursor over first child, make it first, etc
const auto SIDEBYSIDE = NEWPARENT->box.w > NEWPARENT->box.h * *PWIDTHMULTIPLIER;
NEWPARENT->splitTop = !SIDEBYSIDE;
static auto* const PFORCESPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:force_split")->intValue;
static auto* const PERMANENTDIRECTIONOVERRIDE = &g_pConfigManager->getConfigValuePtr("dwindle:permanent_direction_override")->intValue;
static auto* const PSMARTSPLIT = &g_pConfigManager->getConfigValuePtr("dwindle:smart_split")->intValue;
static auto PFORCESPLIT = CConfigValue<Hyprlang::INT>("dwindle:force_split");
static auto PERMANENTDIRECTIONOVERRIDE = CConfigValue<Hyprlang::INT>("dwindle:permanent_direction_override");
static auto PSMARTSPLIT = CConfigValue<Hyprlang::INT>("dwindle:smart_split");
bool horizontalOverride = false;
bool verticalOverride = false;
@@ -536,21 +554,24 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
if (!PMONITOR)
return; // ???
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
g_pHyprRenderer->damageMonitor(PMONITOR);
if (PMONITOR->specialWorkspaceID)
calculateWorkspace(PMONITOR->specialWorkspaceID);
calculateWorkspace(PMONITOR->activeWorkspace);
}
void CHyprDwindleLayout::calculateWorkspace(const int& ws) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(ws);
if (!PWORKSPACE)
return;
g_pHyprRenderer->damageMonitor(PMONITOR);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
if (PMONITOR->specialWorkspaceID) {
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->specialWorkspaceID);
if (TOPNODE && PMONITOR) {
TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
TOPNODE->recalcSizePosRecursive();
}
}
if (!PMONITOR)
return;
if (PWORKSPACE->m_bHasFullscreenWindow) {
// massive hack from the fullscreen func
@@ -571,12 +592,13 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
applyNodeDataToWindow(&fakeNode);
}
// if has fullscreen, don't calculate the rest
return;
}
const auto TOPNODE = getMasterNodeOnWorkspace(PMONITOR->activeWorkspace);
const auto TOPNODE = getMasterNodeOnWorkspace(ws);
if (TOPNODE && PMONITOR) {
if (TOPNODE) {
TOPNODE->box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight};
TOPNODE->recalcSizePosRecursive();
}
@@ -602,13 +624,13 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goal() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goal() + pixResize).y, 20.0));
PWINDOW->updateWindowDecos();
return;
}
const auto PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
const auto PSMARTRESIZING = &g_pConfigManager->getConfigValuePtr("dwindle:smart_resizing")->intValue;
static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("dwindle:smart_resizing");
// get some data about our window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
@@ -621,7 +643,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
if (!m_PseudoDragFlags.started) {
m_PseudoDragFlags.started = true;
const auto pseudoSize = PWINDOW->m_vRealSize.goalv();
const auto pseudoSize = PWINDOW->m_vRealSize.goal();
const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->box.pos() + ((PNODE->box.size() / 2) - (pseudoSize / 2)));
if (mouseOffset.x > 0 && mouseOffset.x < pseudoSize.x && mouseOffset.y > 0 && mouseOffset.y < pseudoSize.y) {
@@ -645,8 +667,10 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn
else
PWINDOW->m_vPseudoSize.y -= pixResize.y * 2;
PWINDOW->m_vPseudoSize.x = std::clamp(PWINDOW->m_vPseudoSize.x, 30.0, PNODE->box.w);
PWINDOW->m_vPseudoSize.y = std::clamp(PWINDOW->m_vPseudoSize.y, 30.0, PNODE->box.h);
CBox wbox = PNODE->box;
wbox.round();
PWINDOW->m_vPseudoSize = {std::clamp(PWINDOW->m_vPseudoSize.x, 30.0, wbox.w), std::clamp(PWINDOW->m_vPseudoSize.y, 30.0, wbox.h)};
PWINDOW->m_vLastFloatingSize = PWINDOW->m_vPseudoSize;
PNODE->recalcSizePosRecursive(*PANIMATE == 0);
@@ -785,7 +809,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
if (!g_pCompositor->windowValidMapped(pWindow))
return;
if (on == pWindow->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
if (on == pWindow->m_bIsFullscreen)
return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -799,10 +823,10 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
// save position and size if floating
if (pWindow->m_bIsFloating && on) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vSize = pWindow->m_vRealSize.goal();
}
// otherwise, accept it.
@@ -847,14 +871,15 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
fakeNode.workspaceID = pWindow->m_iWorkspaceID;
pWindow->m_vPosition = fakeNode.box.pos();
pWindow->m_vSize = fakeNode.box.size();
fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode, true);
applyNodeDataToWindow(&fakeNode);
}
}
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal());
g_pCompositor->changeWindowZOrder(pWindow, true);
@@ -912,6 +937,8 @@ void CHyprDwindleLayout::moveWindowTo(CWindow* pWindow, const std::string& dir)
default: UNREACHABLE();
}
pWindow->setAnimationsToMove();
onWindowRemovedTiling(pWindow);
m_vOverrideFocalPoint = focalPoint;
@@ -934,9 +961,16 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
auto PNODE = getNodeFromWindow(pWindow);
auto PNODE2 = getNodeFromWindow(pWindow2);
if (!PNODE2 || !PNODE) {
if (!PNODE2 || !PNODE)
return;
}
const bool FS1 = pWindow->m_bIsFullscreen;
const bool FS2 = pWindow2->m_bIsFullscreen;
if (FS1)
g_pCompositor->setWindowFullscreen(pWindow, false);
if (FS2)
g_pCompositor->setWindowFullscreen(pWindow2, false);
SDwindleNodeData* ACTIVE1 = nullptr;
SDwindleNodeData* ACTIVE2 = nullptr;
@@ -950,12 +984,14 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
std::swap(pWindow2->m_iWorkspaceID, pWindow->m_iWorkspaceID);
}
pWindow->setAnimationsToMove();
pWindow2->setAnimationsToMove();
// recalc the workspace
getMasterNodeOnWorkspace(PNODE->workspaceID)->recalcSizePosRecursive();
if (PNODE2->workspaceID != PNODE->workspaceID) {
if (PNODE2->workspaceID != PNODE->workspaceID)
getMasterNodeOnWorkspace(PNODE2->workspaceID)->recalcSizePosRecursive();
}
if (ACTIVE1) {
ACTIVE1->box = PNODE->box;
@@ -971,6 +1007,11 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
g_pHyprRenderer->damageWindow(pWindow);
g_pHyprRenderer->damageWindow(pWindow2);
if (FS1)
g_pCompositor->setWindowFullscreen(pWindow2, true);
if (FS2)
g_pCompositor->setWindowFullscreen(pWindow, true);
}
void CHyprDwindleLayout::alterSplitRatio(CWindow* pWindow, float ratio, bool exact) {
@@ -991,6 +1032,8 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str
const auto ARGS = CVarList(message, 0, ' ');
if (ARGS[0] == "togglesplit") {
toggleSplit(header.pWindow);
} else if (ARGS[0] == "swapsplit") {
swapSplit(header.pWindow);
} else if (ARGS[0] == "preselect") {
std::string direction = ARGS[1];
@@ -1044,6 +1087,20 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) {
PNODE->pParent->recalcSizePosRecursive();
}
void CHyprDwindleLayout::swapSplit(CWindow* pWindow) {
const auto PNODE = getNodeFromWindow(pWindow);
if (!PNODE || !PNODE->pParent)
return;
if (pWindow->m_bIsFullscreen)
return;
std::swap(PNODE->pParent->children[0], PNODE->pParent->children[1]);
PNODE->pParent->recalcSizePosRecursive();
}
void CHyprDwindleLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
const auto PNODE = getNodeFromWindow(from);
@@ -1071,3 +1128,48 @@ void CHyprDwindleLayout::onEnable() {
void CHyprDwindleLayout::onDisable() {
m_lDwindleNodesData.clear();
}
Vector2D CHyprDwindleLayout::predictSizeForNewWindowTiled() {
if (!g_pCompositor->m_pLastMonitor)
return {};
// get window candidate
CWindow* candidate = g_pCompositor->m_pLastWindow;
if (!candidate)
candidate = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace);
// create a fake node
SDwindleNodeData node;
if (!candidate)
return g_pCompositor->m_pLastMonitor->vecSize;
else {
const auto PNODE = getNodeFromWindow(candidate);
if (!PNODE)
return {};
node = *PNODE;
node.pWindow = nullptr;
CBox box = PNODE->box;
static auto PFLMULT = CConfigValue<Hyprlang::FLOAT>("dwindle:split_width_multiplier");
bool splitTop = box.h * *PFLMULT > box.w;
const auto SPLITSIDE = !splitTop;
if (SPLITSIDE)
node.box = {{}, {box.w / 2.0, box.h}};
else
node.box = {{}, {box.w, box.h / 2.0}};
// TODO: make this better and more accurate
return node.box.size();
}
return {};
}

View File

@@ -59,6 +59,7 @@ class CHyprDwindleLayout : public IHyprLayout {
virtual void alterSplitRatio(CWindow*, float, bool);
virtual std::string getLayoutName();
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
virtual Vector2D predictSizeForNewWindowTiled();
virtual void onEnable();
virtual void onDisable();
@@ -77,12 +78,14 @@ class CHyprDwindleLayout : public IHyprLayout {
int getNodesOnWorkspace(const int&);
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
void calculateWorkspace(const int& ws);
SDwindleNodeData* getNodeFromWindow(CWindow*);
SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&);
SDwindleNodeData* getMasterNodeOnWorkspace(const int&);
void toggleSplit(CWindow*);
void swapSplit(CWindow*);
eDirection overrideDirection = DIRECTION_DEFAULT;

View File

@@ -2,6 +2,8 @@
#include "../defines.hpp"
#include "../Compositor.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "../config/ConfigValue.hpp"
#include "../desktop/Window.hpp"
void IHyprLayout::onWindowCreated(CWindow* pWindow, eDirection direction) {
if (pWindow->m_bIsFloating) {
@@ -87,7 +89,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
desiredGeometry.y = xy.y;
}
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
static auto PXWLFORCESCALEZERO = CConfigValue<Hyprlang::INT>("xwayland:force_zero_scaling");
if (!PMONITOR) {
Debug::log(ERR, "{:m} has an invalid monitor in onWindowCreatedFloating!!!", pWindow);
@@ -105,7 +107,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
}
// reject any windows with size <= 5x5
if (pWindow->m_vRealSize.goalv().x <= 5 || pWindow->m_vRealSize.goalv().y <= 5)
if (pWindow->m_vRealSize.goal().x <= 5 || pWindow->m_vRealSize.goal().y <= 5)
pWindow->m_vRealSize = PMONITOR->vecSize / 2.f;
if (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect) {
@@ -113,11 +115,11 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
if (pWindow->m_uSurface.xwayland->x != 0 && pWindow->m_uSurface.xwayland->y != 0)
pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords({pWindow->m_uSurface.xwayland->x, pWindow->m_uSurface.xwayland->y});
else
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goalv().x) / 2.f,
PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goalv().y) / 2.f);
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f,
PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f);
} else {
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goalv().x) / 2.f,
PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goalv().y) / 2.f);
pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f,
PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f);
}
} else {
// we respect the size.
@@ -152,7 +154,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
}
if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11)
pWindow->m_vRealSize = pWindow->m_vRealSize.goalv() / PMONITOR->scale;
pWindow->m_vRealSize = pWindow->m_vRealSize.goal() / PMONITOR->scale;
if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect)) {
pWindow->m_vRealPosition.warp();
@@ -160,11 +162,11 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
}
if (pWindow->m_iX11Type != 2) {
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal());
g_pCompositor->changeWindowZOrder(pWindow, true);
} else {
pWindow->m_vPendingReportedSize = pWindow->m_vRealSize.goalv();
pWindow->m_vPendingReportedSize = pWindow->m_vRealSize.goal();
pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize;
}
}
@@ -172,6 +174,7 @@ void IHyprLayout::onWindowCreatedFloating(CWindow* pWindow) {
void IHyprLayout::onBeginDragWindow() {
const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow;
m_iMouseMoveEventCount = 1;
m_vBeginDragSizeXY = Vector2D();
// Window will be floating. Let's check if it's valid. It should be, but I don't like crashing.
@@ -200,22 +203,42 @@ void IHyprLayout::onBeginDragWindow() {
if (!DRAGGINGWINDOW->m_bIsFloating) {
if (g_pInputManager->dragMode == MBIND_MOVE) {
DRAGGINGWINDOW->m_vLastFloatingSize = (DRAGGINGWINDOW->m_vRealSize.goalv() * 0.8489).clamp(Vector2D{5, 5}, Vector2D{}).floor();
DRAGGINGWINDOW->m_vLastFloatingSize = (DRAGGINGWINDOW->m_vRealSize.goal() * 0.8489).clamp(Vector2D{5, 5}, Vector2D{}).floor();
changeWindowFloatingMode(DRAGGINGWINDOW);
DRAGGINGWINDOW->m_bIsFloating = true;
DRAGGINGWINDOW->m_bDraggingTiled = true;
DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize.goalv() / 2.f;
DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize.goal() / 2.f;
}
}
m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal();
m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goalv();
m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goalv();
m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goal();
m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goal();
m_vLastDragXY = m_vBeginDragXY;
// get the grab corner
if (m_vBeginDragXY.x < m_vBeginDragPositionXY.x + m_vBeginDragSizeXY.x / 2.0) {
static auto RESIZECORNER = CConfigValue<Hyprlang::INT>("general:resize_corner");
if (*RESIZECORNER != 0 && *RESIZECORNER <= 4 && DRAGGINGWINDOW->m_bIsFloating) {
switch (*RESIZECORNER) {
case 1:
m_eGrabbedCorner = CORNER_TOPLEFT;
g_pInputManager->setCursorImageUntilUnset("nw-resize");
break;
case 2:
m_eGrabbedCorner = CORNER_TOPRIGHT;
g_pInputManager->setCursorImageUntilUnset("ne-resize");
break;
case 3:
m_eGrabbedCorner = CORNER_BOTTOMRIGHT;
g_pInputManager->setCursorImageUntilUnset("se-resize");
break;
case 4:
m_eGrabbedCorner = CORNER_BOTTOMLEFT;
g_pInputManager->setCursorImageUntilUnset("sw-resize");
break;
}
} else if (m_vBeginDragXY.x < m_vBeginDragPositionXY.x + m_vBeginDragSizeXY.x / 2.0) {
if (m_vBeginDragXY.y < m_vBeginDragPositionXY.y + m_vBeginDragSizeXY.y / 2.0) {
m_eGrabbedCorner = CORNER_TOPLEFT;
g_pInputManager->setCursorImageUntilUnset("nw-resize");
@@ -247,6 +270,8 @@ void IHyprLayout::onBeginDragWindow() {
void IHyprLayout::onEndDragWindow() {
const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow;
m_iMouseMoveEventCount = 1;
if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW)) {
if (DRAGGINGWINDOW) {
g_pInputManager->unsetCursorImage();
@@ -275,7 +300,7 @@ void IHyprLayout::onEndDragWindow() {
return;
if (pWindow->m_sGroupData.pNextWindow && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) {
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW);
pWindow->setGroupCurrent(DRAGGINGWINDOW);
DRAGGINGWINDOW->updateWindowDecos();
@@ -302,19 +327,36 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
return;
}
static auto TIMER = std::chrono::high_resolution_clock::now();
static auto TIMER = std::chrono::high_resolution_clock::now(), MSTIMER = TIMER;
const auto SPECIAL = g_pCompositor->isWorkspaceSpecial(DRAGGINGWINDOW->m_iWorkspaceID);
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);
static auto* const PANIMATEMOUSE = &g_pConfigManager->getConfigValuePtr("misc:animate_mouse_windowdragging")->intValue;
static auto* const PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
static auto PANIMATEMOUSE = CConfigValue<Hyprlang::INT>("misc:animate_mouse_windowdragging");
static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) ||
(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count() <
1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate))
const auto TIMERDELTA = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count();
const auto MSDELTA = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - MSTIMER).count();
const auto MSMONITOR = 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate;
static int totalMs = 0;
bool canSkipUpdate = true;
MSTIMER = std::chrono::high_resolution_clock::now();
if (m_iMouseMoveEventCount == 1)
totalMs = 0;
if (MSMONITOR > 16.0) {
totalMs += MSDELTA < MSMONITOR ? MSDELTA : std::round(totalMs * 1.0 / m_iMouseMoveEventCount);
m_iMouseMoveEventCount += 1;
// check if time-window is enough to skip update on 60hz monitor
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 && g_pInputManager->dragMode != MBIND_MOVE))
return;
TIMER = std::chrono::high_resolution_clock::now();
@@ -325,7 +367,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
if (g_pInputManager->dragMode == MBIND_MOVE) {
CBox wb = {m_vBeginDragPositionXY + DELTA, DRAGGINGWINDOW->m_vRealSize.goalv()};
CBox wb = {m_vBeginDragPositionXY + DELTA, DRAGGINGWINDOW->m_vRealSize.goal()};
wb.round();
if (*PANIMATEMOUSE)
@@ -333,12 +375,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
else
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos());
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal());
} else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) {
if (DRAGGINGWINDOW->m_bIsFloating) {
Vector2D MINSIZE = Vector2D(20, 20);
Vector2D MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW);
Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sAdditionalConfigData.minSize.toUnderlying());
Vector2D MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, DRAGGINGWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying());
Vector2D newSize = m_vBeginDragSizeXY;
Vector2D newPos = m_vBeginDragPositionXY;
@@ -394,14 +436,14 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos());
}
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal());
} else {
resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW);
}
}
// get middle point
Vector2D middle = DRAGGINGWINDOW->m_vRealPosition.vec() + DRAGGINGWINDOW->m_vRealSize.vec() / 2.f;
Vector2D middle = DRAGGINGWINDOW->m_vRealPosition.value() + DRAGGINGWINDOW->m_vRealSize.value() / 2.f;
// and check its monitor
const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle);
@@ -435,18 +477,23 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
EMIT_HOOK_EVENT("changeFloatingMode", pWindow);
if (!TILED) {
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.vec() + pWindow->m_vRealSize.vec() / 2.f);
const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f);
pWindow->m_iMonitorID = PNEWMON->ID;
pWindow->moveToWorkspace(PNEWMON->specialWorkspaceID != 0 ? PNEWMON->specialWorkspaceID : PNEWMON->activeWorkspace);
pWindow->updateGroupOutputs();
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PNEWMON->specialWorkspaceID != 0 ? PNEWMON->specialWorkspaceID : PNEWMON->activeWorkspace);
if (PWORKSPACE->m_bHasFullscreenWindow)
g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false);
// save real pos cuz the func applies the default 5,5 mid
const auto PSAVEDPOS = pWindow->m_vRealPosition.goalv();
const auto PSAVEDSIZE = pWindow->m_vRealSize.goalv();
const auto PSAVEDPOS = pWindow->m_vRealPosition.goal();
const auto PSAVEDSIZE = pWindow->m_vRealSize.goal();
// if the window is pseudo, update its size
if (!pWindow->m_bDraggingTiled)
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goalv();
pWindow->m_vPseudoSize = pWindow->m_vRealSize.goal();
pWindow->m_vLastFloatingSize = PSAVEDSIZE;
@@ -468,10 +515,11 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
g_pCompositor->changeWindowZOrder(pWindow, true);
CBox wb = {pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize};
CBox wb = {pWindow->m_vRealPosition.goal() + (pWindow->m_vRealSize.goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize};
wb.round();
if (DELTALESSTHAN(pWindow->m_vRealSize.vec().x, pWindow->m_vLastFloatingSize.x, 10) && DELTALESSTHAN(pWindow->m_vRealSize.vec().y, pWindow->m_vLastFloatingSize.y, 10)) {
if (DELTALESSTHAN(pWindow->m_vRealSize.value().x, pWindow->m_vLastFloatingSize.x, 10) &&
DELTALESSTHAN(pWindow->m_vRealSize.value().y, pWindow->m_vLastFloatingSize.y, 10)) {
wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}};
}
@@ -505,7 +553,9 @@ void IHyprLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) {
return;
}
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + delta;
PWINDOW->setAnimationsToMove();
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + delta;
g_pHyprRenderer->damageWindow(PWINDOW);
}
@@ -530,7 +580,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
// find whether there is a floating window below this one
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 &&
!w->m_bNoFocus && 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,
w->m_vPosition.y + w->m_vSize.y)) {
return w.get();
@@ -550,7 +600,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
// if not, floating window
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 &&
!w->m_bNoFocus && w.get() != pWindow)
!w->m_sAdditionalConfigData.noFocus && w.get() != pWindow)
return w.get();
}
@@ -591,6 +641,64 @@ void IHyprLayout::bringWindowToTop(CWindow* pWindow) {
void IHyprLayout::requestFocusForWindow(CWindow* pWindow) {
bringWindowToTop(pWindow);
g_pCompositor->focusWindow(pWindow);
g_pCompositor->warpCursorTo(pWindow->middle());
}
Vector2D IHyprLayout::predictSizeForNewWindowFloating(CWindow* pWindow) { // get all rules, see if we have any size overrides.
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() {}

View File

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

View File

@@ -1,7 +1,9 @@
#include "MasterLayout.hpp"
#include "../Compositor.hpp"
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "config/ConfigDataValues.hpp"
#include <ranges>
#include "../config/ConfigValue.hpp"
SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(CWindow* pWindow) {
for (auto& nd : m_lMasterNodesData) {
@@ -41,25 +43,27 @@ SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) {
//create on the fly if it doesn't exist yet
const auto PWORKSPACEDATA = &m_lMasterWorkspacesData.emplace_back();
PWORKSPACEDATA->workspaceID = ws;
const auto orientation = &g_pConfigManager->getConfigValuePtr("master:orientation")->strValue;
const auto layoutoptsForWs = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(ws)).layoutopts;
auto orientationForWs = *orientation;
static auto PORIENTATION = CConfigValue<std::string>("master:orientation");
const auto WORKSPACERULES = g_pConfigManager->getWorkspaceRulesFor(g_pCompositor->getWorkspaceByID(ws));
if (layoutoptsForWs.contains("orientation"))
orientationForWs = layoutoptsForWs.at("orientation");
std::string orientationForWs = *PORIENTATION;
if (orientationForWs == "top") {
PWORKSPACEDATA->orientation = ORIENTATION_TOP;
} else if (orientationForWs == "right") {
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
} else if (orientationForWs == "bottom") {
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
} else if (orientationForWs == "center") {
PWORKSPACEDATA->orientation = ORIENTATION_CENTER;
} else {
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
for (auto& wsRule : WORKSPACERULES) {
if (wsRule.layoutopts.contains("orientation"))
orientationForWs = wsRule.layoutopts.at("orientation");
}
if (orientationForWs == "top")
PWORKSPACEDATA->orientation = ORIENTATION_TOP;
else if (orientationForWs == "right")
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
else if (orientationForWs == "bottom")
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
else if (orientationForWs == "center")
PWORKSPACEDATA->orientation = ORIENTATION_CENTER;
else
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
return PWORKSPACEDATA;
}
@@ -80,7 +84,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
if (pWindow->m_bIsFloating)
return;
static auto* const PNEWTOP = &g_pConfigManager->getConfigValuePtr("master:new_on_top")->intValue;
static auto PNEWTOP = CConfigValue<Hyprlang::INT>("master:new_on_top");
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -89,10 +93,10 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
PNODE->workspaceID = pWindow->m_iWorkspaceID;
PNODE->pWindow = pWindow;
static auto* const PNEWISMASTER = &g_pConfigManager->getConfigValuePtr("master:new_is_master")->intValue;
static auto PNEWISMASTER = CConfigValue<Hyprlang::INT>("master:new_is_master");
const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID);
static auto* const PMFACT = &g_pConfigManager->getConfigValuePtr("master:mfact")->floatValue;
static auto PMFACT = CConfigValue<Hyprlang::FLOAT>("master:mfact");
float lastSplitPercent = *PMFACT;
auto OPENINGON = isWindowTiled(g_pCompositor->m_pLastWindow) && g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID ?
@@ -112,7 +116,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
m_lMasterNodesData.remove(*PNODE);
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
(*USECURRPOS ? OPENINGON->pWindow : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow);
OPENINGON->pWindow->setGroupCurrent(pWindow);
@@ -128,7 +132,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection direc
pWindow->applyGroupRules();
static auto* const PDROPATCURSOR = &g_pConfigManager->getConfigValuePtr("master:drop_at_cursor")->intValue;
static auto PDROPATCURSOR = CConfigValue<Hyprlang::INT>("master:drop_at_cursor");
const auto PWORKSPACEDATA = getMasterWorkspaceData(pWindow->m_iWorkspaceID);
eOrientation orientation = PWORKSPACEDATA->orientation;
const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE);
@@ -239,11 +243,10 @@ void CHyprMasterLayout::onWindowRemovedTiling(CWindow* pWindow) {
const auto WORKSPACEID = PNODE->workspaceID;
const auto MASTERSLEFT = getMastersOnWorkspace(WORKSPACEID);
static const auto* SMALLSPLIT = &g_pConfigManager->getConfigValuePtr("master:allow_small_split")->intValue;
static auto SMALLSPLIT = CConfigValue<Hyprlang::INT>("master:allow_small_split");
pWindow->updateSpecialRenderData();
if (pWindow->m_bIsFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
if (PNODE->isMaster && (MASTERSLEFT <= 1 || *SMALLSPLIT == 1)) {
@@ -286,16 +289,24 @@ void CHyprMasterLayout::recalculateMonitor(const int& monid) {
if (!PMONITOR)
return;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
g_pHyprRenderer->damageMonitor(PMONITOR);
if (PMONITOR->specialWorkspaceID)
calculateWorkspace(PMONITOR->specialWorkspaceID);
calculateWorkspace(PMONITOR->activeWorkspace);
}
void CHyprMasterLayout::calculateWorkspace(const int& ws) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(ws);
if (!PWORKSPACE)
return;
g_pHyprRenderer->damageMonitor(PMONITOR);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
if (PMONITOR->specialWorkspaceID) {
calculateWorkspace(PMONITOR->specialWorkspaceID);
}
if (!PMONITOR)
return;
if (PWORKSPACE->m_bHasFullscreenWindow) {
// massive hack from the fullscreen func
@@ -312,34 +323,45 @@ void CHyprMasterLayout::recalculateMonitor(const int& monid) {
fakeNode.workspaceID = PWORKSPACE->m_iID;
PFULLWINDOW->m_vPosition = fakeNode.position;
PFULLWINDOW->m_vSize = fakeNode.size;
fakeNode.ignoreFullscreenChecks = true;
applyNodeDataToWindow(&fakeNode);
}
// if has fullscreen, don't calculate the rest
return;
}
// calc the WS
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)
return;
// dynamic workspace rules
const auto WORKSPACERULES = g_pConfigManager->getWorkspaceRulesFor(g_pCompositor->getWorkspaceByID(ws));
std::string orientationForWs;
for (auto& wsRule : WORKSPACERULES) {
if (wsRule.layoutopts.contains("orientation"))
orientationForWs = wsRule.layoutopts.at("orientation");
}
if (orientationForWs == "top")
PWORKSPACEDATA->orientation = ORIENTATION_TOP;
else if (orientationForWs == "right")
PWORKSPACEDATA->orientation = ORIENTATION_RIGHT;
else if (orientationForWs == "bottom")
PWORKSPACEDATA->orientation = ORIENTATION_BOTTOM;
else if (orientationForWs == "center")
PWORKSPACEDATA->orientation = ORIENTATION_CENTER;
else if (orientationForWs == "left")
PWORKSPACEDATA->orientation = ORIENTATION_LEFT;
eOrientation orientation = PWORKSPACEDATA->orientation;
bool centerMasterWindow = false;
static auto* const ALWAYSCENTER = &g_pConfigManager->getConfigValuePtr("master:always_center_master")->intValue;
static auto* const PSMARTRESIZING = &g_pConfigManager->getConfigValuePtr("master:smart_resizing")->intValue;
static auto ALWAYSCENTER = CConfigValue<Hyprlang::INT>("master:always_center_master");
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing");
const auto MASTERS = getMastersOnWorkspace(PWORKSPACE->m_iID);
const auto WINDOWS = getNodesOnWorkspace(PWORKSPACE->m_iID);
@@ -626,20 +648,28 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
const auto PWINDOW = pNode->pWindow;
// get specific gaps and rules for this workspace,
// if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID));
const auto WORKSPACERULES = g_pConfigManager->getWorkspaceRulesFor(g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID));
if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks)
return;
PWINDOW->updateSpecialRenderData();
static auto* const PGAPSIN = &g_pConfigManager->getConfigValuePtr("general:gaps_in")->intValue;
static auto* const PGAPSOUT = &g_pConfigManager->getConfigValuePtr("general:gaps_out")->intValue;
static auto* const PNOGAPSWHENONLY = &g_pConfigManager->getConfigValuePtr("master:no_gaps_when_only")->intValue;
static auto* const PANIMATE = &g_pConfigManager->getConfigValuePtr("misc:animate_manual_resizes")->intValue;
static auto PNOGAPSWHENONLY = CConfigValue<Hyprlang::INT>("master:no_gaps_when_only");
static auto PANIMATE = CConfigValue<Hyprlang::INT>("misc:animate_manual_resizes");
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
auto* PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData();
auto* PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData();
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT);
auto gapsIn = *PGAPSIN;
auto gapsOut = *PGAPSOUT;
for (auto& wsRule : WORKSPACERULES) {
if (wsRule.gapsIn.has_value())
gapsIn = wsRule.gapsIn.value();
if (wsRule.gapsOut.has_value())
gapsOut = wsRule.gapsOut.value();
}
if (!g_pCompositor->windowValidMapped(PWINDOW)) {
Debug::log(ERR, "Node {} holding invalid {}!!", pNode, PWINDOW);
@@ -653,10 +683,17 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
(getNodesOnWorkspace(PWINDOW->m_iWorkspaceID) == 1 ||
(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.decorate = WORKSPACERULE.decorate.value_or(true);
PWINDOW->m_sSpecialRenderData.rounding = false;
PWINDOW->m_sSpecialRenderData.shadow = false;
PWINDOW->m_sSpecialRenderData.border = (*PNOGAPSWHENONLY == 2);
PWINDOW->m_sSpecialRenderData.decorate = true;
for (auto& wsRule : WORKSPACERULES) {
if (wsRule.border.has_value())
PWINDOW->m_sSpecialRenderData.border = wsRule.border.value();
if (wsRule.decorate.has_value())
PWINDOW->m_sSpecialRenderData.decorate = wsRule.decorate.value();
}
PWINDOW->updateWindowDecos();
@@ -665,7 +702,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft;
PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight);
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
return;
}
@@ -673,9 +710,9 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
auto calcPos = PWINDOW->m_vPosition;
auto calcSize = PWINDOW->m_vSize;
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut : gapsIn, DISPLAYTOP ? gapsOut : gapsIn);
const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut.left : gapsIn.left, DISPLAYTOP ? gapsOut.top : gapsIn.top);
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? gapsOut : gapsIn, DISPLAYBOTTOM ? gapsOut : gapsIn);
const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? gapsOut.right : gapsIn.right, DISPLAYBOTTOM ? gapsOut.bottom : gapsIn.bottom);
calcPos = calcPos + OFFSETTOPLEFT;
calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT;
@@ -684,8 +721,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) {
calcPos = calcPos + RESERVED.topLeft;
calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight);
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID)) {
static auto* const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("master:special_scale_factor")->floatValue;
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID) && !PWINDOW->m_bIsFullscreen) {
static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("master:special_scale_factor");
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
wb.round(); // avoid rounding mess
@@ -729,15 +766,15 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne
const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goalv() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goalv() + pixResize).y, 20.0));
PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goal() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goal() + pixResize).y, 20.0));
PWINDOW->updateWindowDecos();
return;
}
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PMONITOR->activeWorkspace);
static auto* const ALWAYSCENTER = &g_pConfigManager->getConfigValuePtr("master:always_center_master")->intValue;
static auto* const PSMARTRESIZING = &g_pConfigManager->getConfigValuePtr("master:smart_resizing")->intValue;
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID);
static auto ALWAYSCENTER = CConfigValue<Hyprlang::INT>("master:always_center_master");
static auto PSMARTRESIZING = CConfigValue<Hyprlang::INT>("master:smart_resizing");
eOrientation orientation = PWORKSPACEDATA->orientation;
bool centered = orientation == ORIENTATION_CENTER && (*ALWAYSCENTER == 1);
@@ -867,7 +904,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
if (!g_pCompositor->windowValidMapped(pWindow))
return;
if (on == pWindow->m_bIsFullscreen || g_pCompositor->isWorkspaceSpecial(pWindow->m_iWorkspaceID))
if (on == pWindow->m_bIsFullscreen)
return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -881,10 +918,10 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
// save position and size if floating
if (pWindow->m_bIsFloating && on) {
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal();
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vPosition = pWindow->m_vRealPosition.goal();
pWindow->m_vSize = pWindow->m_vRealSize.goal();
}
// otherwise, accept it.
@@ -938,7 +975,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
g_pCompositor->updateWindowAnimatedDecorationValues(pWindow);
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goalv());
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal());
g_pCompositor->changeWindowZOrder(pWindow, true);
@@ -968,11 +1005,15 @@ void CHyprMasterLayout::moveWindowTo(CWindow* pWindow, const std::string& dir) {
const auto PWINDOW2 = g_pCompositor->getWindowInDirection(pWindow, dir[0]);
pWindow->setAnimationsToMove();
if (pWindow->m_iWorkspaceID != PWINDOW2->m_iWorkspaceID) {
// if different monitors, send to monitor
onWindowRemovedTiling(pWindow);
pWindow->moveToWorkspace(PWINDOW2->m_iWorkspaceID);
pWindow->m_iMonitorID = PWINDOW2->m_iMonitorID;
const auto pMonitor = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
g_pCompositor->setActiveMonitor(pMonitor);
onWindowCreatedTiling(pWindow);
} else {
// if same monitor, switch windows
@@ -989,8 +1030,6 @@ void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
if (!PNODE2 || !PNODE)
return;
const auto inheritFullscreen = prepareLoseFocus(pWindow);
if (PNODE->workspaceID != PNODE2->workspaceID) {
std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID);
std::swap(pWindow2->m_iWorkspaceID, pWindow->m_iWorkspaceID);
@@ -1000,14 +1039,15 @@ void CHyprMasterLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
PNODE->pWindow = pWindow2;
PNODE2->pWindow = pWindow;
pWindow->setAnimationsToMove();
pWindow2->setAnimationsToMove();
recalculateMonitor(pWindow->m_iMonitorID);
if (PNODE2->workspaceID != PNODE->workspaceID)
recalculateMonitor(pWindow2->m_iMonitorID);
g_pHyprRenderer->damageWindow(pWindow);
g_pHyprRenderer->damageWindow(pWindow2);
prepareNewFocus(pWindow2, inheritFullscreen);
}
void CHyprMasterLayout::alterSplitRatio(CWindow* pWindow, float ratio, bool exact) {
@@ -1048,35 +1088,27 @@ CWindow* CHyprMasterLayout::getNextWindow(CWindow* pWindow, bool next) {
return CANDIDATE == nodes.end() ? nullptr : CANDIDATE->pWindow;
}
bool CHyprMasterLayout::prepareLoseFocus(CWindow* pWindow) {
if (!pWindow)
return false;
//if the current window is fullscreen, make it normal again if we are about to lose focus
if (pWindow->m_bIsFullscreen) {
g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL);
static auto* const INHERIT = &g_pConfigManager->getConfigValuePtr("master:inherit_fullscreen")->intValue;
return *INHERIT == 1;
}
return false;
}
void CHyprMasterLayout::prepareNewFocus(CWindow* pWindow, bool inheritFullscreen) {
if (!pWindow)
return;
if (inheritFullscreen)
g_pCompositor->setWindowFullscreen(pWindow, true, g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID)->m_efFullscreenMode);
}
std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::string message) {
auto switchToWindow = [&](CWindow* PWINDOWTOCHANGETO) {
if (!g_pCompositor->windowValidMapped(PWINDOWTOCHANGETO))
return;
if (header.pWindow->m_bIsFullscreen) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
static auto INHERITFULLSCREEN = CConfigValue<Hyprlang::INT>("master:inherit_fullscreen");
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL);
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
if (*INHERITFULLSCREEN)
g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE);
} else {
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->middle());
}
g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO;
g_pInputManager->simulateMouseMovement();
g_pInputManager->m_pForcedFocus = nullptr;
};
CVarList vars(message, 0, ' ');
@@ -1112,21 +1144,17 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (PMASTER->pWindow != PWINDOW) {
const auto NEWMASTER = PWINDOW;
const bool newFocusToChild = vars.size() >= 2 && vars[1] == "child";
const bool inheritFullscreen = prepareLoseFocus(NEWMASTER);
switchWindows(NEWMASTER, NEWCHILD);
const auto NEWFOCUS = newFocusToChild ? NEWCHILD : NEWMASTER;
switchToWindow(NEWFOCUS);
prepareNewFocus(NEWFOCUS, inheritFullscreen);
} else {
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) {
const auto NEWMASTER = n.pWindow;
const bool inheritFullscreen = prepareLoseFocus(NEWCHILD);
switchWindows(NEWMASTER, NEWCHILD);
const bool newFocusToMaster = vars.size() >= 2 && vars[1] == "master";
const auto NEWFOCUS = newFocusToMaster ? NEWMASTER : NEWCHILD;
switchToWindow(NEWFOCUS);
prepareNewFocus(NEWFOCUS, inheritFullscreen);
break;
}
}
@@ -1144,8 +1172,6 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (!PWINDOW)
return 0;
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
const auto PMASTER = getMasterNodeOnWorkspace(PWINDOW->m_iWorkspaceID);
if (!PMASTER)
@@ -1153,7 +1179,6 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (PMASTER->pWindow != PWINDOW) {
switchToWindow(PMASTER->pWindow);
prepareNewFocus(PMASTER->pWindow, inheritFullscreen);
} else if (vars.size() >= 2 && vars[1] == "master") {
return 0;
} else {
@@ -1161,7 +1186,6 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
for (auto& n : m_lMasterNodesData) {
if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) {
switchToWindow(n.pWindow);
prepareNewFocus(n.pWindow, inheritFullscreen);
break;
}
}
@@ -1174,22 +1198,16 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (!PWINDOW)
return 0;
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
const auto PNEXTWINDOW = getNextWindow(PWINDOW, true);
switchToWindow(PNEXTWINDOW);
prepareNewFocus(PNEXTWINDOW, inheritFullscreen);
} else if (command == "cycleprev") {
const auto PWINDOW = header.pWindow;
if (!PWINDOW)
return 0;
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
const auto PPREVWINDOW = getNextWindow(PWINDOW, false);
switchToWindow(PPREVWINDOW);
prepareNewFocus(PPREVWINDOW, inheritFullscreen);
} else if (command == "swapnext") {
if (!g_pCompositor->windowValidMapped(header.pWindow))
return 0;
@@ -1202,9 +1220,9 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true);
if (PWINDOWTOSWAPWITH) {
prepareLoseFocus(header.pWindow);
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL);
switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
g_pCompositor->focusWindow(header.pWindow);
switchToWindow(header.pWindow);
}
} else if (command == "swapprev") {
if (!g_pCompositor->windowValidMapped(header.pWindow))
@@ -1218,9 +1236,9 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false);
if (PWINDOWTOSWAPWITH) {
prepareLoseFocus(header.pWindow);
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL);
switchWindows(header.pWindow, PWINDOWTOSWAPWITH);
g_pCompositor->focusWindow(header.pWindow);
switchToWindow(header.pWindow);
}
} else if (command == "addmaster") {
if (!g_pCompositor->windowValidMapped(header.pWindow))
@@ -1233,11 +1251,11 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
const auto WINDOWS = getNodesOnWorkspace(header.pWindow->m_iWorkspaceID);
const auto MASTERS = getMastersOnWorkspace(header.pWindow->m_iWorkspaceID);
static const auto* SMALLSPLIT = &g_pConfigManager->getConfigValuePtr("master:allow_small_split")->intValue;
static auto SMALLSPLIT = CConfigValue<Hyprlang::INT>("master:allow_small_split");
if (MASTERS + 2 > WINDOWS && *SMALLSPLIT == 0)
return 0;
prepareLoseFocus(header.pWindow);
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL);
if (!PNODE || PNODE->isMaster) {
// first non-master node
@@ -1269,7 +1287,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (WINDOWS < 2 || MASTERS < 2)
return 0;
prepareLoseFocus(header.pWindow);
g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL);
if (!PNODE || !PNODE->isMaster) {
// first non-master node
@@ -1290,7 +1308,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
if (!PWINDOW)
return 0;
prepareLoseFocus(PWINDOW);
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID);
@@ -1345,9 +1363,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
nd.isMaster = true;
const auto NEWMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), nd);
m_lMasterNodesData.splice(OLDMASTERIT, m_lMasterNodesData, NEWMASTERIT);
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
switchToWindow(nd.pWindow);
prepareNewFocus(nd.pWindow, inheritFullscreen);
OLDMASTER->isMaster = false;
m_lMasterNodesData.splice(m_lMasterNodesData.end(), m_lMasterNodesData, OLDMASTERIT);
break;
@@ -1373,9 +1389,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
nd.isMaster = true;
const auto NEWMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), nd);
m_lMasterNodesData.splice(OLDMASTERIT, m_lMasterNodesData, NEWMASTERIT);
const bool inheritFullscreen = prepareLoseFocus(PWINDOW);
switchToWindow(nd.pWindow);
prepareNewFocus(nd.pWindow, inheritFullscreen);
OLDMASTER->isMaster = false;
m_lMasterNodesData.splice(m_lMasterNodesData.begin(), m_lMasterNodesData, OLDMASTERIT);
break;
@@ -1402,7 +1416,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi
if (!PWINDOW)
return;
prepareLoseFocus(PWINDOW);
g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL);
const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->m_iWorkspaceID);
@@ -1456,6 +1470,33 @@ void CHyprMasterLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
applyNodeDataToWindow(PNODE);
}
Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() {
static auto PNEWISMASTER = CConfigValue<Hyprlang::INT>("master:new_is_master");
if (!g_pCompositor->m_pLastMonitor)
return {};
const int NODES = getNodesOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace);
if (NODES <= 0)
return g_pCompositor->m_pLastMonitor->vecSize;
const auto MASTER = getMasterNodeOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace);
if (!MASTER) // wtf
return {};
if (*PNEWISMASTER) {
return MASTER->size;
} else {
const auto SLAVES = NODES - getMastersOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace);
// TODO: make this better
return {g_pCompositor->m_pLastMonitor->vecSize.x - MASTER->size.x, g_pCompositor->m_pLastMonitor->vecSize.y / (SLAVES + 1)};
}
return {};
}
void CHyprMasterLayout::onEnable() {
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_bIsFloating || !w->m_bIsMapped || w->isHidden())

View File

@@ -65,6 +65,7 @@ class CHyprMasterLayout : public IHyprLayout {
virtual void alterSplitRatio(CWindow*, float, bool);
virtual std::string getLayoutName();
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
virtual Vector2D predictSizeForNewWindowTiled();
virtual void onEnable();
virtual void onDisable();
@@ -86,8 +87,6 @@ class CHyprMasterLayout : public IHyprLayout {
void calculateWorkspace(const int&);
CWindow* getNextWindow(CWindow*, bool);
int getMastersOnWorkspace(const int&);
bool prepareLoseFocus(CWindow*);
void prepareNewFocus(CWindow*, bool inherit_fullscreen);
friend struct SMasterNodeData;
friend struct SMasterWorkspaceData;

View File

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

View File

@@ -1,6 +1,9 @@
#include "AnimationManager.hpp"
#include "../Compositor.hpp"
#include "HookSystemManager.hpp"
#include "macros.hpp"
#include "../config/ConfigValue.hpp"
#include "../desktop/Window.hpp"
int wlTick(void* data) {
if (g_pAnimationManager)
@@ -53,16 +56,16 @@ void CAnimationManager::tick() {
bool animGlobalDisabled = false;
static auto* const PANIMENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue;
static auto PANIMENABLED = CConfigValue<Hyprlang::INT>("animations:enabled");
if (!*PANIMENABLED)
animGlobalDisabled = true;
static auto* const PSHADOWSENABLED = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
static auto* const PSHADOWSENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:drop_shadow");
const auto DEFAULTBEZIER = m_mBezierCurves.find("default");
std::vector<CAnimatedVariable*> animationEndedVars;
std::vector<CBaseAnimatedVariable*> animationEndedVars;
for (auto& av : m_vActiveAnimatedVariables) {
@@ -82,9 +85,17 @@ void CAnimationManager::tick() {
CMonitor* PMONITOR = nullptr;
bool animationsDisabled = animGlobalDisabled;
CBox WLRBOXPREV = {0, 0, 0, 0};
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);
if (!PMONITOR)
continue;
@@ -93,15 +104,42 @@ void CAnimationManager::tick() {
PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
if (!PMONITOR)
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...
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->isHidden() && w->m_bIsMapped && w->m_bIsFloating)
if (!w->m_bIsMapped || w->isHidden() || w->m_iWorkspaceID != PWORKSPACE->m_iID)
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_iWorkspaceID != PWORKSPACE->m_iID || w->m_bPinned)
continue;
g_pHyprRenderer->damageWindow(w.get());
}
} else if (PLAYER) {
WLRBOXPREV = PLAYER->geometry;
// "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);
if (!PMONITOR)
continue;
@@ -113,78 +151,48 @@ void CAnimationManager::tick() {
// beziers are with a switch unforto
// TODO: maybe do something cleaner
switch (av->m_eVarType) {
case AVARTYPE_FLOAT: {
auto updateVariable = [&]<Animable T>(CAnimatedVariable<T>& av) {
// for disabled anims just warp
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp(false);
break;
if (av.m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av.warp(false);
return;
}
if (SPENT >= 1.f || av->m_fBegun == av->m_fGoal) {
av->warp(false);
break;
if (SPENT >= 1.f || av.m_Begun == av.m_Goal) {
av.warp(false);
return;
}
const auto DELTA = av->m_fGoal - av->m_fBegun;
const auto BEZIER = m_mBezierCurves.find(av->m_pConfig->pValues->internalBezier);
const auto DELTA = av.m_Goal - av.m_Begun;
const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier);
if (BEZIER != m_mBezierCurves.end())
av->m_fValue = av->m_fBegun + BEZIER->second.getYForPoint(SPENT) * DELTA;
av.m_Value = av.m_Begun + DELTA * BEZIER->second.getYForPoint(SPENT);
else
av->m_fValue = av->m_fBegun + DEFAULTBEZIER->second.getYForPoint(SPENT) * DELTA;
av.m_Value = av.m_Begun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT);
};
switch (av->m_Type) {
case AVARTYPE_FLOAT: {
auto typedAv = static_cast<CAnimatedVariable<float>*>(av);
updateVariable(*typedAv);
break;
}
case AVARTYPE_VECTOR: {
// for disabled anims just warp
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp(false);
break;
}
if (SPENT >= 1.f || av->m_vBegun == av->m_vGoal) {
av->warp(false);
break;
}
const auto DELTA = av->m_vGoal - av->m_vBegun;
const auto BEZIER = m_mBezierCurves.find(av->m_pConfig->pValues->internalBezier);
if (BEZIER != m_mBezierCurves.end())
av->m_vValue = av->m_vBegun + DELTA * BEZIER->second.getYForPoint(SPENT);
else
av->m_vValue = av->m_vBegun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT);
auto typedAv = static_cast<CAnimatedVariable<Vector2D>*>(av);
updateVariable(*typedAv);
break;
}
case AVARTYPE_COLOR: {
// for disabled anims just warp
if (av->m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) {
av->warp(false);
auto typedAv = static_cast<CAnimatedVariable<CColor>*>(av);
updateVariable(*typedAv);
break;
}
if (SPENT >= 1.f || av->m_cBegun == av->m_cGoal) {
av->warp(false);
break;
default: UNREACHABLE();
}
const auto DELTA = av->m_cGoal - av->m_cBegun;
const auto BEZIER = m_mBezierCurves.find(av->m_pConfig->pValues->internalBezier);
if (BEZIER != m_mBezierCurves.end())
av->m_cValue = av->m_cBegun + DELTA * BEZIER->second.getYForPoint(SPENT);
else
av->m_cValue = av->m_cBegun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT);
break;
}
default: {
;
}
}
// set size and pos if valid, but only if damage policy entire (dont if border for example)
if (g_pCompositor->windowValidMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && PWINDOW->m_iX11Type != 2)
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal());
// check if we did not finish animating. If so, trigger onAnimationEnd.
if (!av->isBeingAnimated())
@@ -199,58 +207,36 @@ void CAnimationManager::tick() {
switch (av->m_eDamagePolicy) {
case AVARDAMAGE_ENTIRE: {
g_pHyprRenderer->damageBox(&WLRBOXPREV);
if (PWINDOW) {
PWINDOW->updateWindowDecos();
g_pHyprRenderer->damageWindow(PWINDOW);
} else if (PWORKSPACE) {
for (auto& w : g_pCompositor->m_vWindows) {
if (!w->m_bIsMapped || w->isHidden())
continue;
if (w->m_iWorkspaceID != PWORKSPACE->m_iID)
if (!g_pCompositor->windowValidMapped(w.get()) || w->m_iWorkspaceID != PWORKSPACE->m_iID)
continue;
w->updateWindowDecos();
if (w->m_bIsFloating) {
auto bb = w->getFullWindowBoundingBox();
bb.translate(PWORKSPACE->m_vRenderOffset.vec());
g_pHyprRenderer->damageBox(&bb);
}
// damage any workspace window that is on any monitor
if (!w->m_bPinned)
g_pHyprRenderer->damageWindow(w.get());
}
} else if (PLAYER) {
if (PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR);
// some fucking layers miss 1 pixel???
CBox expandBox = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()};
expandBox.expand(5);
g_pHyprRenderer->damageBox(&expandBox);
}
break;
}
case AVARDAMAGE_BORDER: {
RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!");
// TODO: move this to the border class
// damage only the border.
static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
const auto ROUNDINGSIZE = *PROUNDING + 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.vec().x, PWINDOW->m_vRealPosition.vec().y, PWINDOW->m_vRealSize.vec().x, PWINDOW->m_vRealSize.vec().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
const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER);
PDECO->damageEntire();
break;
}
@@ -318,23 +304,23 @@ bool CAnimationManager::bezierExists(const std::string& bezier) {
//
void CAnimationManager::animationPopin(CWindow* pWindow, bool close, float minPerc) {
const auto GOALPOS = pWindow->m_vRealPosition.goalv();
const auto GOALSIZE = pWindow->m_vRealSize.goalv();
const auto GOALPOS = pWindow->m_vRealPosition.goal();
const auto GOALSIZE = pWindow->m_vRealSize.goal();
if (!close) {
pWindow->m_vRealSize.setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}));
pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_vValue / 2.f);
pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_Value / 2.f);
} else {
pWindow->m_vRealSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y});
pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_vGoal / 2.f;
pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_Goal / 2.f;
}
}
void CAnimationManager::animationSlide(CWindow* pWindow, std::string force, bool close) {
pWindow->m_vRealSize.warp(false); // size we preserve in slide
const auto GOALPOS = pWindow->m_vRealPosition.goalv();
const auto GOALSIZE = pWindow->m_vRealSize.goalv();
const auto GOALPOS = pWindow->m_vRealPosition.goal();
const auto GOALSIZE = pWindow->m_vRealSize.goal();
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
@@ -508,6 +494,27 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config,
if (style == "loop" || style == "once")
return "";
return "unknown style";
} else if (config.starts_with("layers")) {
if (style == "fade" || style == "" || style == "slide")
return "";
else if (style.starts_with("popin")) {
// try parsing
float minPerc = 0.f;
if (style.find("%") != std::string::npos) {
try {
auto percstr = style.substr(style.find_last_of(' '));
minPerc = std::stoi(percstr.substr(0, percstr.length() - 1));
} catch (std::exception& e) { return "invalid minperc"; }
return "";
}
minPerc; // fix warning
return "";
}
return "";
return "unknown style";
} else {
return "animation has no styles";
}

View File

@@ -5,9 +5,10 @@
#include <unordered_map>
#include "../helpers/AnimatedVariable.hpp"
#include "../helpers/BezierCurve.hpp"
#include "../Window.hpp"
#include "../helpers/Timer.hpp"
class CWindow;
class CAnimationManager {
public:
CAnimationManager();
@@ -28,8 +29,8 @@ class CAnimationManager {
std::unordered_map<std::string, CBezierCurve> getAllBeziers();
std::vector<CAnimatedVariable*> m_vAnimatedVariables;
std::vector<CAnimatedVariable*> m_vActiveAnimatedVariables;
std::vector<CBaseAnimatedVariable*> m_vAnimatedVariables;
std::vector<CBaseAnimatedVariable*> m_vActiveAnimatedVariables;
wl_event_source* m_pAnimationTick;

View File

@@ -0,0 +1,234 @@
#include "CursorManager.hpp"
#include "Compositor.hpp"
#include "../config/ConfigValue.hpp"
extern "C" {
#include <wlr/interfaces/wlr_buffer.h>
#include <wlr/types/wlr_xcursor_manager.h>
}
static int cursorAnimTimer(void* data) {
g_pCursorManager->tickAnimatedCursor();
return 1;
}
CCursorManager::CCursorManager() {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.empty() ? nullptr : m_szTheme.c_str());
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
auto SIZE = getenv("HYPRCURSOR_SIZE");
if (SIZE) {
try {
m_iSize = std::stoi(SIZE);
} catch (...) { ; }
}
SIZE = getenv("XCURSOR_SIZE");
if (SIZE && m_iSize == 0) {
try {
m_iSize = std::stoi(SIZE);
} catch (...) { ; }
}
if (m_iSize == 0)
m_iSize = 24;
m_pWLRXCursorMgr = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"), m_iSize);
wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0);
m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr);
updateTheme();
g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateTheme(); });
}
void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) {
std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; });
}
static void cursorBufferDestroy(struct wlr_buffer* wlr_buffer) {
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
g_pCursorManager->dropBufferRef(buffer->parent);
}
static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t flags, void** data, uint32_t* format, size_t* stride) {
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE)
return false;
*data = cairo_image_surface_get_data(buffer->surface);
*stride = cairo_image_surface_get_stride(buffer->surface);
*format = DRM_FORMAT_ARGB8888;
return true;
}
static void cursorBufferEndDataPtr(struct wlr_buffer* wlr_buffer) {
;
}
//
static const wlr_buffer_impl bufferImpl = {
.destroy = cursorBufferDestroy,
.begin_data_ptr_access = cursorBufferBeginDataPtr,
.end_data_ptr_access = cursorBufferEndDataPtr,
};
CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) {
wlrBuffer.surface = surf;
wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y);
wlrBuffer.parent = this;
}
CCursorManager::CCursorBuffer::~CCursorBuffer() {
; // will be freed in .destroy
}
wlr_buffer* CCursorManager::getCursorBuffer() {
return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr;
}
void CCursorManager::setCursorSurface(wlr_surface* surf, const Vector2D& hotspot) {
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspot.x, hotspot.y);
m_bOurBufferConnected = false;
}
void CCursorManager::setCursorFromName(const std::string& name) {
static auto PUSEHYPRCURSOR = CConfigValue<Hyprlang::INT>("misc:enable_hyprcursor");
if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR) {
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, m_pWLRXCursorMgr, name.c_str());
return;
}
m_sCurrentCursorShapeData = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo);
if (m_sCurrentCursorShapeData.images.size() < 1) {
// fallback to a default if available
constexpr const std::array<const char*, 2> fallbackShapes = {"default", "left_ptr"};
for (auto& s : fallbackShapes) {
m_sCurrentCursorShapeData = m_pHyprcursor->getShape(s, m_sCurrentStyleInfo);
if (m_sCurrentCursorShapeData.images.size() > 0)
break;
}
if (m_sCurrentCursorShapeData.images.size() < 1) {
Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName");
return;
}
}
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface,
Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
if (g_pCompositor->m_sWLRCursor) {
wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[0].hotspotX / m_fCursorScale,
m_sCurrentCursorShapeData.images[0].hotspotY / m_fCursorScale, m_fCursorScale);
if (m_vCursorBuffers.size() > 1)
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
}
m_bOurBufferConnected = true;
if (m_sCurrentCursorShapeData.images.size() > 1) {
// animated
wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[0].delay);
m_iCurrentAnimationFrame = 0;
} else {
// disarm
wl_event_source_timer_update(m_pAnimationTimer, 0);
}
}
void CCursorManager::tickAnimatedCursor() {
if (m_sCurrentCursorShapeData.images.size() < 2 || !m_bOurBufferConnected)
return;
m_iCurrentAnimationFrame++;
if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size())
m_iCurrentAnimationFrame = 0;
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(
m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface,
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size},
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}));
if (g_pCompositor->m_sWLRCursor)
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_fCursorScale);
wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay);
}
SCursorImageData CCursorManager::dataFor(const std::string& name) {
if (!m_pHyprcursor->valid())
return {};
const auto IMAGES = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo);
if (IMAGES.images.empty())
return {};
return IMAGES.images[0];
}
void CCursorManager::setXWaylandCursor(wlr_xwayland* xwayland) {
const auto CURSOR = dataFor("left_ptr");
if (CURSOR.surface) {
wlr_xwayland_set_cursor(xwayland, cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), CURSOR.size, CURSOR.size, CURSOR.hotspotX,
CURSOR.hotspotY);
} else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) {
wlr_xwayland_set_cursor(xwayland, XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, XCURSOR->images[0]->width, XCURSOR->images[0]->height,
XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y);
} else
Debug::log(ERR, "CursorManager: no valid cursor for xwayland");
}
void CCursorManager::updateTheme() {
float highestScale = 1.0;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->scale > highestScale)
highestScale = m->scale;
}
if (highestScale * m_iSize == m_sCurrentStyleInfo.size)
return;
if (m_sCurrentStyleInfo.size && m_pHyprcursor->valid())
m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo);
m_sCurrentStyleInfo.size = m_iSize * highestScale;
m_fCursorScale = highestScale;
if (m_pHyprcursor->valid())
m_pHyprcursor->loadThemeStyle(m_sCurrentStyleInfo);
setCursorFromName("left_ptr");
for (auto& m : g_pCompositor->m_vMonitors) {
m->forceFullFrames = 5;
g_pCompositor->scheduleFrameForMonitor(m.get());
}
}
void CCursorManager::changeTheme(const std::string& name, const int size) {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(name.empty() ? "" : name.c_str());
m_szTheme = name;
m_iSize = size;
if (!m_pHyprcursor->valid())
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", m_szTheme);
updateTheme();
}

View File

@@ -0,0 +1,71 @@
#pragma once
#include <string>
#include <hyprcursor/hyprcursor.hpp>
#include <memory>
#include "../includes.hpp"
#include "../helpers/Vector2D.hpp"
struct wlr_buffer;
struct wlr_xcursor_manager;
struct wlr_xwayland;
class CCursorManager {
public:
CCursorManager();
wlr_buffer* getCursorBuffer();
void setCursorFromName(const std::string& name);
void setCursorSurface(wlr_surface* surf, const Vector2D& hotspot);
void changeTheme(const std::string& name, const int size);
void updateTheme();
SCursorImageData dataFor(const std::string& name); // for xwayland
void setXWaylandCursor(wlr_xwayland* xwayland);
void tickAnimatedCursor();
class CCursorBuffer {
public:
CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot);
~CCursorBuffer();
struct SCursorWlrBuffer {
wlr_buffer base;
cairo_surface_t* surface = nullptr;
bool dropped = false;
CCursorBuffer* parent = nullptr;
} wlrBuffer;
private:
Vector2D size;
Vector2D hotspot;
friend class CCursorManager;
};
void dropBufferRef(CCursorBuffer* ref);
bool m_bOurBufferConnected = false;
private:
std::vector<std::unique_ptr<CCursorBuffer>> m_vCursorBuffers;
std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor;
std::string m_szTheme = "";
int m_iSize = 0;
float m_fCursorScale = 1.0;
Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo;
wl_event_source* m_pAnimationTimer = nullptr;
int m_iCurrentAnimationFrame = 0;
Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData;
// xcursor fallback
wlr_xcursor_manager* m_pWLRXCursorMgr = nullptr;
};
inline std::unique_ptr<CCursorManager> g_pCursorManager;

View File

@@ -15,17 +15,74 @@
#include <sys/ioctl.h>
#include <string>
#include <algorithm>
CEventManager::CEventManager() {}
int fdHandleWrite(int fd, uint32_t mask, void* data) {
const auto PEVMGR = (CEventManager*)data;
return PEVMGR->onFDWrite(fd, mask);
}
auto removeFD = [&](int fd) -> void {
const auto ACCEPTEDFDS = (std::deque<std::pair<int, wl_event_source*>>*)data;
for (auto it = ACCEPTEDFDS->begin(); it != ACCEPTEDFDS->end();) {
int socket2HandleWrite(int fd, uint32_t mask, void* data) {
const auto PEVMGR = (CEventManager*)data;
return PEVMGR->onSocket2Write(fd, mask);
}
void CEventManager::startThread() {
m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (m_iSocketFD < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work.");
return;
}
sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX};
std::string socketPath = "/tmp/hypr/" + g_pCompositor->m_szInstanceSignature + "/.socket2.sock";
strncpy(SERVERADDRESS.sun_path, socketPath.c_str(), sizeof(SERVERADDRESS.sun_path) - 1);
bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS));
// 10 max queued.
listen(m_iSocketFD, 10);
m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, socket2HandleWrite, this);
}
int CEventManager::onSocket2Write(int fd, uint32_t mask) {
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) {
Debug::log(ERR, "Socket2 hangup?? IPC broke");
wl_event_source_remove(m_pEventSource);
close(fd);
return 0;
}
sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress);
const auto ACCEPTEDCONNECTION = accept4(m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK);
if (ACCEPTEDCONNECTION > 0) {
Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION);
// add to event loop so we can close it when we need to
m_dAcceptedSocketFDs.push_back(
std::make_pair<>(ACCEPTEDCONNECTION, wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, WL_EVENT_READABLE, fdHandleWrite, this)));
} else {
Debug::log(ERR, "Socket2 failed receiving connection, errno: {}", errno);
close(fd);
}
return 0;
}
int CEventManager::onFDWrite(int fd, uint32_t mask) {
auto removeFD = [this](int fd) -> void {
for (auto it = m_dAcceptedSocketFDs.begin(); it != m_dAcceptedSocketFDs.end();) {
if (it->first == fd) {
wl_event_source_remove(it->second); // remove this fd listener
it = ACCEPTEDFDS->erase(it);
it = m_dAcceptedSocketFDs.erase(it);
} else {
it++;
}
@@ -58,52 +115,6 @@ int fdHandleWrite(int fd, uint32_t mask, void* data) {
return 0;
}
void CEventManager::startThread() {
m_tThread = std::thread([&]() {
const auto SOCKET = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (SOCKET < 0) {
Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work.");
return;
}
sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX};
std::string socketPath = "/tmp/hypr/" + g_pCompositor->m_szInstanceSignature + "/.socket2.sock";
strncpy(SERVERADDRESS.sun_path, socketPath.c_str(), sizeof(SERVERADDRESS.sun_path) - 1);
bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS));
// 10 max queued.
listen(SOCKET, 10);
sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress);
Debug::log(LOG, "Hypr socket 2 started at {}", socketPath);
while (1) {
const auto ACCEPTEDCONNECTION = accept4(SOCKET, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
if (ACCEPTEDCONNECTION > 0) {
// new connection!
int flagsNew = fcntl(ACCEPTEDCONNECTION, F_GETFL, 0);
fcntl(ACCEPTEDCONNECTION, F_SETFL, flagsNew | O_NONBLOCK);
Debug::log(LOG, "Socket 2 accepted a new client at FD {}", ACCEPTEDCONNECTION);
// add to event loop so we can close it when we need to
m_dAcceptedSocketFDs.push_back(
{ACCEPTEDCONNECTION, wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, WL_EVENT_READABLE, fdHandleWrite, &m_dAcceptedSocketFDs)});
}
}
close(SOCKET);
});
m_tThread.detach();
}
void CEventManager::flushEvents() {
eventQueueMutex.lock();
@@ -129,7 +140,9 @@ void CEventManager::postEvent(const SHyprIPCEvent event) {
}
std::thread(
[&](const SHyprIPCEvent ev) {
[this](SHyprIPCEvent ev) {
std::replace(ev.data.begin(), ev.data.end(), '\n', ' ');
eventQueueMutex.lock();
m_dQueuedEvents.push_back(ev);
eventQueueMutex.unlock();

View File

@@ -21,6 +21,11 @@ class CEventManager {
std::thread m_tThread;
int m_iSocketFD = -1;
int onSocket2Write(int fd, uint32_t mask);
int onFDWrite(int fd, uint32_t mask);
private:
void flushEvents();
@@ -28,6 +33,8 @@ class CEventManager {
std::deque<SHyprIPCEvent> m_dQueuedEvents;
std::deque<std::pair<int, wl_event_source*>> m_dAcceptedSocketFDs;
wl_event_source* m_pEventSource = nullptr;
};
inline std::unique_ptr<CEventManager> g_pEventManager;

View File

@@ -2,6 +2,7 @@
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "debug/Log.hpp"
#include "helpers/VarList.hpp"
#include "../config/ConfigValue.hpp"
#include <regex>
@@ -24,6 +25,8 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["killactive"] = killActive;
m_mDispatchers["closewindow"] = kill;
m_mDispatchers["togglefloating"] = toggleActiveFloating;
m_mDispatchers["setfloating"] = setActiveFloating;
m_mDispatchers["settiled"] = setActiveTiled;
m_mDispatchers["workspace"] = changeworkspace;
m_mDispatchers["renameworkspace"] = renameWorkspace;
m_mDispatchers["fullscreen"] = fullscreenActive;
@@ -39,6 +42,7 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["changegroupactive"] = changeGroupActive;
m_mDispatchers["movegroupwindow"] = moveGroupWindow;
m_mDispatchers["togglesplit"] = toggleSplit;
m_mDispatchers["swapsplit"] = swapSplit;
m_mDispatchers["splitratio"] = alterSplitRatio;
m_mDispatchers["focusmonitor"] = focusMonitor;
m_mDispatchers["movecursortocorner"] = moveCursorToCorner;
@@ -94,18 +98,9 @@ void CKeybindManager::addKeybind(SKeybind kb) {
m_pActiveKeybind = nullptr;
}
void CKeybindManager::removeKeybind(uint32_t mod, const std::string& key) {
void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) {
for (auto it = m_lKeybinds.begin(); it != m_lKeybinds.end(); ++it) {
if (isNumber(key) && std::stoi(key) > 9) {
const uint32_t KEYNUM = std::stoi(key);
if (it->modmask == mod && it->keycode == KEYNUM) {
it = m_lKeybinds.erase(it);
if (it == m_lKeybinds.end())
break;
}
} else if (it->modmask == mod && it->key == key) {
if (it->modmask == mod && it->key == key.key && it->keycode == key.keycode && it->catchAll == key.catchAll) {
it = m_lKeybinds.erase(it);
if (it == m_lKeybinds.end())
@@ -163,12 +158,19 @@ void CKeybindManager::updateXKBTranslationState() {
m_pXKBTranslationState = nullptr;
}
const auto FILEPATH = g_pConfigManager->getString("input:kb_file");
const auto RULES = g_pConfigManager->getString("input:kb_rules");
const auto MODEL = g_pConfigManager->getString("input:kb_model");
const auto LAYOUT = g_pConfigManager->getString("input:kb_layout");
const auto VARIANT = g_pConfigManager->getString("input:kb_variant");
const auto OPTIONS = g_pConfigManager->getString("input:kb_options");
static auto PFILEPATH = CConfigValue<std::string>("input:kb_file");
static auto PRULES = CConfigValue<std::string>("input:kb_rules");
static auto PMODEL = CConfigValue<std::string>("input:kb_model");
static auto PLAYOUT = CConfigValue<std::string>("input:kb_layout");
static auto PVARIANT = CConfigValue<std::string>("input:kb_variant");
static auto POPTIONS = CConfigValue<std::string>("input:kb_options");
const std::string FILEPATH = std::string{*PFILEPATH} == STRVAL_EMPTY ? "" : *PFILEPATH;
const std::string RULES = std::string{*PRULES} == STRVAL_EMPTY ? "" : *PRULES;
const std::string MODEL = std::string{*PMODEL} == STRVAL_EMPTY ? "" : *PMODEL;
const std::string LAYOUT = std::string{*PLAYOUT} == STRVAL_EMPTY ? "" : *PLAYOUT;
const std::string VARIANT = std::string{*PVARIANT} == STRVAL_EMPTY ? "" : *PVARIANT;
const std::string OPTIONS = std::string{*POPTIONS} == STRVAL_EMPTY ? "" : *POPTIONS;
xkb_rule_names rules = {.rules = RULES.c_str(), .model = MODEL.c_str(), .layout = LAYOUT.c_str(), .variant = VARIANT.c_str(), .options = OPTIONS.c_str()};
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
@@ -226,7 +228,7 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
const auto PNEWMAINWORKSPACE = g_pCompositor->getWorkspaceByID(monitor->activeWorkspace);
g_pCompositor->setActiveMonitor(monitor);
g_pInputManager->unconstrainMouse();
PNEWMAINWORKSPACE->rememberPrevWorkspace(PWORKSPACE);
const auto PNEWWORKSPACE = monitor->specialWorkspaceID != 0 ? g_pCompositor->getWorkspaceByID(monitor->specialWorkspaceID) : PNEWMAINWORKSPACE;
@@ -235,10 +237,15 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
if (PNEWWINDOW) {
g_pCompositor->focusWindow(PNEWWINDOW);
g_pCompositor->warpCursorTo(PNEWWINDOW->middle());
g_pInputManager->m_pForcedFocus = PNEWWINDOW;
g_pInputManager->simulateMouseMovement();
g_pInputManager->m_pForcedFocus = nullptr;
} else {
g_pCompositor->focusWindow(nullptr);
g_pCompositor->warpCursorTo(monitor->middle());
}
g_pCompositor->setActiveMonitor(monitor);
return true;
}
@@ -249,6 +256,9 @@ void CKeybindManager::switchToWindow(CWindow* PWINDOWTOCHANGETO) {
if (PWINDOWTOCHANGETO == PLASTWINDOW || !PWINDOWTOCHANGETO)
return;
// remove constraints
g_pInputManager->unconstrainMouse();
if (PLASTWINDOW && PLASTWINDOW->m_iWorkspaceID == PWINDOWTOCHANGETO->m_iWorkspaceID && PLASTWINDOW->m_bIsFullscreen) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PLASTWINDOW->m_iWorkspaceID);
const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
@@ -296,7 +306,7 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
const auto KEYCODE = e->keycode + 8; // Because to xkbcommon it's +8 from libinput
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbTranslationState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(wlr_keyboard_from_input_device(pKeyboard->keyboard)->xkb_state, KEYCODE);
if (handleInternalKeybinds(internalKeysym))
@@ -315,6 +325,7 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
.keycode = KEYCODE,
.modmaskAtPressTime = MODS,
.sent = true,
.submapAtPress = m_szCurrentSelectedSubmap,
};
bool suppressEvent = false;
@@ -345,7 +356,8 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
bool foundInPressedKeys = false;
for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) {
if (it->keycode == KEYCODE) {
suppressEvent = handleKeybinds(MODS, *it, false);
if (it->submapAtPress == m_szCurrentSelectedSubmap)
handleKeybinds(MODS, *it, false);
foundInPressedKeys = true;
suppressEvent = !it->sent;
it = m_dPressedKeys.erase(it);
@@ -368,7 +380,7 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
static auto* const PDELAY = &g_pConfigManager->getConfigValuePtr("binds:scroll_event_delay")->intValue;
static auto PDELAY = CConfigValue<Hyprlang::INT>("binds:scroll_event_delay");
if (m_tScrollTimer.getMillis() < *PDELAY) {
m_tScrollTimer.reset();
@@ -378,12 +390,12 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
m_tScrollTimer.reset();
bool found = false;
if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_VERTICAL) {
if (e->source == WL_POINTER_AXIS_SOURCE_WHEEL && e->orientation == WL_POINTER_AXIS_VERTICAL_SCROLL) {
if (e->delta < 0)
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true);
else
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true);
} else if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_HORIZONTAL) {
} else if (e->source == WL_POINTER_AXIS_SOURCE_WHEEL && e->orientation == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
if (e->delta < 0)
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true);
else
@@ -414,7 +426,7 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
.modmaskAtPressTime = MODS,
};
if (e->state == WLR_BUTTON_PRESSED) {
if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) {
m_dPressedKeys.push_back(KEY);
suppressEvent = handleKeybinds(MODS, KEY, true);
@@ -448,7 +460,7 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
}
void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) {
if (e->state == WLR_BUTTON_PRESSED) {
if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) {
mouse("1resizewindow");
} else {
mouse("0resizewindow");
@@ -489,6 +501,17 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
if (g_pCompositor->m_sSeat.exclusiveClient)
Debug::log(LOG, "Keybind handling only locked (inhibitor)");
static auto PDISABLEINHIBIT = CConfigValue<Hyprlang::INT>("binds:disable_keybind_grabbing");
if (!*PDISABLEINHIBIT && !m_lShortcutInhibitors.empty()) {
for (auto& i : m_lShortcutInhibitors) {
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);
return false;
}
}
}
for (auto& k : m_lKeybinds) {
const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "mouse";
const bool SPECIALTRIGGERED =
@@ -506,10 +529,25 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi
} else if (k.keycode != 0) {
if (key.keycode != k.keycode)
continue;
} else if (k.catchAll) {
if (found)
continue;
} else {
// oMg such performance hit!!11!
// this little maneouver is gonna cost us 4µs
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
if (KBKEY == 0) {
// Keysym failed to resolve from the key name of the currently iterated bind.
// This happens for names such as `switch:off:Lid Switch` as well as some keys
// (such as yen and ro).
//
// We can't let compare a 0-value with currently pressed key below,
// because if this key also have no keysym (i.e. key.keysym == 0) it will incorrectly trigger the
// currently iterated bind. That's confirmed to be happening with yen and ro keys.
continue;
}
const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY);
if (key.keysym != KBKEY && key.keysym != KBKEYUPPER)
@@ -762,9 +800,9 @@ uint64_t CKeybindManager::spawnRaw(std::string args) {
close(socket[1]);
read(socket[0], &grandchild, sizeof(grandchild));
close(socket[0]);
// clear child and leave child to init
// clear child and leave grandchild to init
waitpid(child, NULL, 0);
if (child < 0) {
if (grandchild < 0) {
Debug::log(LOG, "Fail to create the second fork");
return 0;
}
@@ -794,9 +832,21 @@ void CKeybindManager::clearKeybinds() {
}
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 toggleActiveFloatingCore(std::string args, std::optional<bool> floatState) {
CWindow* PWINDOW = nullptr;
if (args != "" && args != "active" && args.length() > 1)
if (args != "active" && args.length() > 1)
PWINDOW = g_pCompositor->getWindowByRegex(args);
else
PWINDOW = g_pCompositor->m_pLastWindow;
@@ -804,12 +854,15 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
if (!PWINDOW)
return;
if (floatState.has_value() && floatState == PWINDOW->m_bIsFloating)
return;
// remove drag status
g_pInputManager->currentlyDraggedWindow = nullptr;
if (PWINDOW->m_sGroupData.pNextWindow && PWINDOW->m_sGroupData.pNextWindow != PWINDOW) {
const auto PCURRENT = PWINDOW->getGroupCurrent();
PCURRENT->m_bIsFloating = !PCURRENT->m_bIsFloating;
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PCURRENT);
@@ -820,10 +873,12 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
curr->updateSpecialRenderData();
curr = curr->m_sGroupData.pNextWindow;
}
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
} else {
PWINDOW->m_bIsFloating = !PWINDOW->m_bIsFloating;
PWINDOW->updateDynamicRules();
g_pCompositor->updateWorkspaceWindows(PWINDOW->m_iWorkspaceID);
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW);
}
@@ -841,8 +896,8 @@ void CKeybindManager::centerWindow(std::string args) {
if (args == "1")
RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f;
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goalv() / 2.f + RESERVEDOFFSET;
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goalv();
PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET;
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal();
}
void CKeybindManager::toggleActivePseudo(std::string args) {
@@ -863,9 +918,9 @@ void CKeybindManager::changeworkspace(std::string args) {
// Workspace_back_and_forth being enabled means that an attempt to switch to
// the current workspace will instead switch to the previous.
static auto* const PBACKANDFORTH = &g_pConfigManager->getConfigValuePtr("binds:workspace_back_and_forth")->intValue;
static auto* const PALLOWWORKSPACECYCLES = &g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles")->intValue;
static auto* const PWORKSPACECENTERON = &g_pConfigManager->getConfigValuePtr("binds:workspace_center_on")->intValue;
static auto PBACKANDFORTH = CConfigValue<Hyprlang::INT>("binds:workspace_back_and_forth");
static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
static auto PWORKSPACECENTERON = CConfigValue<Hyprlang::INT>("binds:workspace_center_on");
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
@@ -960,9 +1015,9 @@ void CKeybindManager::fullscreenActive(std::string args) {
if (!PWINDOW)
return;
if (g_pCompositor->isWorkspaceSpecial(PWINDOW->m_iWorkspaceID))
return;
PWINDOW->m_bDontSendFullscreen = false;
if (args == "2")
PWINDOW->m_bDontSendFullscreen = true;
g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL);
}
@@ -997,7 +1052,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
auto pWorkspace = g_pCompositor->getWorkspaceByID(WORKSPACEID);
CMonitor* pMonitor = nullptr;
const auto POLDWS = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
static auto* const PALLOWWORKSPACECYCLES = &g_pConfigManager->getConfigValuePtr("binds:allow_workspace_cycles")->intValue;
static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
g_pHyprRenderer->damageWindow(PWINDOW);
@@ -1075,7 +1130,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
}
void CKeybindManager::moveFocusTo(std::string args) {
static auto* const PFULLCYCLE = &g_pConfigManager->getConfigValuePtr("binds:movefocus_cycles_fullscreen")->intValue;
static auto PFULLCYCLE = CConfigValue<Hyprlang::INT>("binds:movefocus_cycles_fullscreen");
char arg = args[0];
if (!isDirection(args)) {
@@ -1089,9 +1144,6 @@ void CKeybindManager::moveFocusTo(std::string args) {
return;
}
// remove constraints
g_pInputManager->unconstrainMouse();
const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->m_bIsFullscreen ?
(arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) :
g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
@@ -1107,7 +1159,7 @@ void CKeybindManager::moveFocusTo(std::string args) {
if (tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg)))
return;
static auto* const PNOFALLBACK = &g_pConfigManager->getConfigValuePtr("general:no_focus_fallback")->intValue;
static auto PNOFALLBACK = CConfigValue<Hyprlang::INT>("general:no_focus_fallback");
if (*PNOFALLBACK)
return;
@@ -1126,9 +1178,6 @@ void CKeybindManager::focusUrgentOrLast(std::string args) {
if (!PWINDOWURGENT && !PWINDOWPREV)
return;
// remove constraints
g_pInputManager->unconstrainMouse();
switchToWindow(PWINDOWURGENT ? PWINDOWURGENT : PWINDOWPREV);
}
@@ -1139,9 +1188,6 @@ void CKeybindManager::focusCurrentOrLast(std::string args) {
if (!PWINDOWPREV)
return;
// remove constraints
g_pInputManager->unconstrainMouse();
switchToWindow(PWINDOWPREV);
}
@@ -1195,14 +1241,14 @@ void CKeybindManager::moveActiveTo(std::string args) {
switch (arg) {
case 'l': vPos.x = PMONITOR->vecReservedTopLeft.x + BORDERSIZE + PMONITOR->vecPosition.x; break;
case 'r': vPos.x = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize.goalv().x - BORDERSIZE + PMONITOR->vecPosition.x; break;
case 'r': vPos.x = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize.goal().x - BORDERSIZE + PMONITOR->vecPosition.x; break;
case 't':
case 'u': vPos.y = PMONITOR->vecReservedTopLeft.y + BORDERSIZE + PMONITOR->vecPosition.y; break;
case 'b':
case 'd': vPos.y = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize.goalv().y - BORDERSIZE + PMONITOR->vecPosition.y; break;
case 'd': vPos.y = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize.goal().y - BORDERSIZE + PMONITOR->vecPosition.y; break;
}
PLASTWINDOW->m_vRealPosition = Vector2D(vPos.x != 0 ? vPos.x : PLASTWINDOW->m_vRealPosition.goalv().x, vPos.y != 0 ? vPos.y : PLASTWINDOW->m_vRealPosition.goalv().y);
PLASTWINDOW->m_vRealPosition = Vector2D(vPos.x != 0 ? vPos.x : PLASTWINDOW->m_vRealPosition.goal().x, vPos.y != 0 ? vPos.y : PLASTWINDOW->m_vRealPosition.goal().y);
return;
}
@@ -1286,6 +1332,21 @@ void CKeybindManager::toggleSplit(std::string args) {
g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "togglesplit");
}
void CKeybindManager::swapSplit(std::string args) {
SLayoutMessageHeader header;
header.pWindow = g_pCompositor->m_pLastWindow;
if (!header.pWindow)
return;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(header.pWindow->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow)
return;
g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "swapsplit");
}
void CKeybindManager::alterSplitRatio(std::string args) {
std::optional<float> splitResult;
bool exact = false;
@@ -1335,22 +1396,22 @@ void CKeybindManager::moveCursorToCorner(std::string arg) {
switch (CORNER) {
case 0:
// bottom left
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PWINDOW->m_vRealPosition.vec().x,
PWINDOW->m_vRealPosition.vec().y + PWINDOW->m_vRealSize.vec().y);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PWINDOW->m_vRealPosition.value().x,
PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y);
break;
case 1:
// bottom right
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PWINDOW->m_vRealPosition.vec().x + PWINDOW->m_vRealSize.vec().x,
PWINDOW->m_vRealPosition.vec().y + PWINDOW->m_vRealSize.vec().y);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x,
PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y);
break;
case 2:
// top right
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PWINDOW->m_vRealPosition.vec().x + PWINDOW->m_vRealSize.vec().x,
PWINDOW->m_vRealPosition.vec().y);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x,
PWINDOW->m_vRealPosition.value().y);
break;
case 3:
// top left
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PWINDOW->m_vRealPosition.vec().x, PWINDOW->m_vRealPosition.vec().y);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y);
break;
}
}
@@ -1415,8 +1476,8 @@ void CKeybindManager::workspaceOpt(std::string args) {
continue;
if (!w->m_bRequestsFloat && w->m_bIsFloating != PWORKSPACE->m_bDefaultFloating) {
const auto SAVEDPOS = w->m_vRealPosition.vec();
const auto SAVEDSIZE = w->m_vRealSize.vec();
const auto SAVEDPOS = w->m_vRealPosition.value();
const auto SAVEDSIZE = w->m_vRealSize.value();
w->m_bIsFloating = PWORKSPACE->m_bDefaultFloating;
g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(w);
@@ -1425,8 +1486,8 @@ void CKeybindManager::workspaceOpt(std::string args) {
w->m_vRealPosition.setValueAndWarp(SAVEDPOS);
w->m_vRealSize.setValueAndWarp(SAVEDSIZE);
g_pXWaylandManager->setWindowSize(w, SAVEDSIZE);
w->m_vRealSize = w->m_vRealSize.vec() + Vector2D(4, 4);
w->m_vRealPosition = w->m_vRealPosition.vec() - Vector2D(2, 2);
w->m_vRealSize = w->m_vRealSize.value() + Vector2D(4, 4);
w->m_vRealPosition = w->m_vRealPosition.value() - Vector2D(2, 2);
}
}
}
@@ -1453,20 +1514,24 @@ void CKeybindManager::renameWorkspace(std::string args) {
}
void CKeybindManager::exitHyprland(std::string argz) {
g_pInputManager->m_bExitTriggered = true;
g_pCompositor->m_bExitTriggered = true;
}
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
CMonitor* PMONITOR = g_pCompositor->getMonitorFromString(args);
if (!PMONITOR)
if (!PMONITOR) {
Debug::log(ERR, "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist");
return;
}
// get the current workspace
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
if (!PCURRENTWORKSPACE)
if (!PCURRENTWORKSPACE) {
Debug::log(ERR, "moveCurrentWorkspaceToMonitor invalid workspace!");
return;
}
g_pCompositor->moveWorkspaceToMonitor(PCURRENTWORKSPACE, PMONITOR);
}
@@ -1505,50 +1570,60 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
std::string workspaceName;
const int WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
int workspaceID = getWorkspaceIDFromString(args, workspaceName);
if (WORKSPACEID == WORKSPACE_INVALID) {
if (workspaceID == WORKSPACE_INVALID) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!");
return;
}
const auto PCURRMONITOR = g_pCompositor->getMonitorFromCursor();
const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor;
if (!PCURRMONITOR) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!");
return;
}
auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
auto pWorkspace = g_pCompositor->getWorkspaceByID(workspaceID);
if (!PWORKSPACE) {
PWORKSPACE = g_pCompositor->createNewWorkspace(WORKSPACEID, PCURRMONITOR->ID);
if (!pWorkspace) {
pWorkspace = g_pCompositor->createNewWorkspace(workspaceID, PCURRMONITOR->ID);
// we can skip the moving, since it's already on the current monitor
changeworkspace(PWORKSPACE->getConfigName());
changeworkspace(pWorkspace->getConfigName());
return;
}
if (PWORKSPACE->m_iMonitorID != PCURRMONITOR->ID) {
const auto POLDMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
static auto PBACKANDFORTH = CConfigValue<Hyprlang::INT>("binds:workspace_back_and_forth");
if (*PBACKANDFORTH && PCURRMONITOR->activeWorkspace == workspaceID && pWorkspace->m_sPrevWorkspace.iID != -1) {
const int PREVWORKSPACEID = pWorkspace->m_sPrevWorkspace.iID;
const auto PREVWORKSPACENAME = pWorkspace->m_sPrevWorkspace.name;
// Workspace to focus is previous workspace
pWorkspace = g_pCompositor->getWorkspaceByID(PREVWORKSPACEID);
if (!pWorkspace)
pWorkspace = g_pCompositor->createNewWorkspace(PREVWORKSPACEID, PCURRMONITOR->ID, PREVWORKSPACENAME);
workspaceID = pWorkspace->m_iID;
}
if (pWorkspace->m_iMonitorID != PCURRMONITOR->ID) {
const auto POLDMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID);
if (!POLDMONITOR) { // wat
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!");
return;
}
if (POLDMONITOR->activeWorkspace == WORKSPACEID) {
if (POLDMONITOR->activeWorkspace == workspaceID) {
g_pCompositor->swapActiveWorkspaces(POLDMONITOR, PCURRMONITOR);
return;
} else {
g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PCURRMONITOR, true);
g_pCompositor->moveWorkspaceToMonitor(pWorkspace, PCURRMONITOR, true);
}
}
changeworkspace(PWORKSPACE->getConfigName());
changeworkspace(pWorkspace->getConfigName());
}
void CKeybindManager::toggleSpecialWorkspace(std::string args) {
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
std::string workspaceName = "";
int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName);
@@ -1558,7 +1633,7 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) {
}
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;
for (auto& m : g_pCompositor->m_vMonitors) {
@@ -1590,7 +1665,7 @@ void CKeybindManager::forceRendererReload(std::string args) {
if (!m->output)
continue;
auto rule = g_pConfigManager->getMonitorRuleFor(m->szName, m->szDescription);
auto rule = g_pConfigManager->getMonitorRuleFor(*m);
if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) {
overAgain = true;
break;
@@ -1605,14 +1680,14 @@ void CKeybindManager::resizeActive(std::string args) {
if (!g_pCompositor->m_pLastWindow || g_pCompositor->m_pLastWindow->m_bIsFullscreen)
return;
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealSize.goalv());
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealSize.goal());
if (SIZ.x < 1 || SIZ.y < 1)
return;
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - g_pCompositor->m_pLastWindow->m_vRealSize.goalv());
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - g_pCompositor->m_pLastWindow->m_vRealSize.goal());
if (g_pCompositor->m_pLastWindow->m_vRealSize.goalv().x > 1 && g_pCompositor->m_pLastWindow->m_vRealSize.goalv().y > 1)
if (g_pCompositor->m_pLastWindow->m_vRealSize.goal().x > 1 && g_pCompositor->m_pLastWindow->m_vRealSize.goal().y > 1)
g_pCompositor->m_pLastWindow->setHidden(false);
}
@@ -1620,9 +1695,9 @@ void CKeybindManager::moveActive(std::string args) {
if (!g_pCompositor->m_pLastWindow || g_pCompositor->m_pLastWindow->m_bIsFullscreen)
return;
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealPosition.goalv());
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, g_pCompositor->m_pLastWindow->m_vRealPosition.goal());
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - g_pCompositor->m_pLastWindow->m_vRealPosition.goalv());
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - g_pCompositor->m_pLastWindow->m_vRealPosition.goal());
}
void CKeybindManager::moveWindow(std::string args) {
@@ -1640,9 +1715,9 @@ void CKeybindManager::moveWindow(std::string args) {
if (PWINDOW->m_bIsFullscreen)
return;
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goalv());
const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goal());
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PWINDOW->m_vRealPosition.goalv(), PWINDOW);
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PWINDOW->m_vRealPosition.goal(), PWINDOW);
}
void CKeybindManager::resizeWindow(std::string args) {
@@ -1660,14 +1735,14 @@ void CKeybindManager::resizeWindow(std::string args) {
if (PWINDOW->m_bIsFullscreen)
return;
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goalv());
const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goal());
if (SIZ.x < 1 || SIZ.y < 1)
return;
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize.goalv(), CORNER_NONE, PWINDOW);
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize.goal(), CORNER_NONE, PWINDOW);
if (PWINDOW->m_vRealSize.goalv().x > 1 && PWINDOW->m_vRealSize.goalv().y > 1)
if (PWINDOW->m_vRealSize.goal().x > 1 && PWINDOW->m_vRealSize.goal().y > 1)
PWINDOW->setHidden(false);
}
@@ -1706,16 +1781,39 @@ void CKeybindManager::focusWindow(std::string regexp) {
Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle);
if (g_pCompositor->m_pLastMonitor->activeWorkspace != PWINDOW->m_iWorkspaceID) {
Debug::log(LOG, "Fake executing workspace to move focus");
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
if (!PWORKSPACE) {
Debug::log(ERR, "BUG THIS: null workspace in focusWindow");
return;
}
if (g_pCompositor->m_pLastMonitor->activeWorkspace != PWINDOW->m_iWorkspaceID) {
Debug::log(LOG, "Fake executing workspace to move focus");
changeworkspace(PWORKSPACE->getConfigName());
}
if (PWORKSPACE->m_bHasFullscreenWindow) {
const auto FSWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
const auto FSMODE = PWORKSPACE->m_efFullscreenMode;
if (PWINDOW->m_bIsFloating) {
// don't make floating implicitly fs
if (!PWINDOW->m_bCreatedOverFullscreen) {
g_pCompositor->changeWindowZOrder(PWINDOW, true);
g_pCompositor->updateFullscreenFadeOnWorkspace(PWORKSPACE);
}
g_pCompositor->focusWindow(PWINDOW);
} else {
if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned)
g_pCompositor->setWindowFullscreen(FSWINDOW, false, FULLSCREEN_FULL);
g_pCompositor->focusWindow(PWINDOW);
if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned)
g_pCompositor->setWindowFullscreen(PWINDOW, true, FSMODE);
}
} else
g_pCompositor->focusWindow(PWINDOW);
g_pCompositor->warpCursorTo(PWINDOW->middle());
@@ -1781,20 +1879,20 @@ void CKeybindManager::pass(std::string regexp) {
if (g_pKeybindManager->m_uLastCode != 0)
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_PRESSED);
else
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WLR_BUTTON_PRESSED);
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_PRESSED);
} else if (g_pKeybindManager->m_iPassPressed == 0)
if (g_pKeybindManager->m_uLastCode != 0)
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_RELEASED);
else
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WLR_BUTTON_RELEASED);
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_RELEASED);
else {
// dynamic call of the dispatcher
if (g_pKeybindManager->m_uLastCode != 0) {
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_PRESSED);
wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_RELEASED);
} else {
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WLR_BUTTON_PRESSED);
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WLR_BUTTON_RELEASED);
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_PRESSED);
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_RELEASED);
}
}
@@ -1918,7 +2016,7 @@ void CKeybindManager::pinActive(std::string args) {
CWindow* PWINDOW = nullptr;
if (args != "" && args != "active" && args.length() > 1)
if (args != "active" && args.length() > 1)
PWINDOW = g_pCompositor->getWindowByRegex(args);
else
PWINDOW = g_pCompositor->m_pLastWindow;
@@ -1940,6 +2038,9 @@ void CKeybindManager::pinActive(std::string args) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
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) {
@@ -2070,7 +2171,7 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property!
static const auto* USECURRPOS = &g_pConfigManager->getConfigValuePtr("group:insert_after_current")->intValue;
static auto USECURRPOS = CConfigValue<Hyprlang::INT>("group:insert_after_current");
pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail();
pWindowInDirection->insertWindowToGroup(pWindow);
@@ -2085,7 +2186,7 @@ void CKeybindManager::moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDi
}
void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir) {
static auto* const BFOCUSREMOVEDWINDOW = &g_pConfigManager->getConfigValuePtr("group:focus_removed_window")->intValue;
static auto BFOCUSREMOVEDWINDOW = CConfigValue<Hyprlang::INT>("group:focus_removed_window");
const auto PWINDOWPREV = pWindow->getGroupPrevious();
eDirection direction;
@@ -2124,7 +2225,7 @@ void CKeybindManager::moveWindowOutOfGroup(CWindow* pWindow, const std::string&
void CKeybindManager::moveIntoGroup(std::string args) {
char arg = args[0];
static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue;
static auto PIGNOREGROUPLOCK = CConfigValue<Hyprlang::INT>("binds:ignore_group_lock");
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked)
return;
@@ -2152,12 +2253,17 @@ void CKeybindManager::moveIntoGroup(std::string args) {
}
void CKeybindManager::moveOutOfGroup(std::string args) {
static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue;
static auto PIGNOREGROUPLOCK = CConfigValue<Hyprlang::INT>("binds:ignore_group_lock");
if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked)
return;
const auto PWINDOW = g_pCompositor->m_pLastWindow;
CWindow* PWINDOW = nullptr;
if (args != "active" && args.length() > 1)
PWINDOW = g_pCompositor->getWindowByRegex(args);
else
PWINDOW = g_pCompositor->m_pLastWindow;
if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow)
return;
@@ -2168,7 +2274,7 @@ void CKeybindManager::moveOutOfGroup(std::string args) {
void CKeybindManager::moveWindowOrGroup(std::string args) {
char arg = args[0];
static auto* const PIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue;
static auto PIGNOREGROUPLOCK = CConfigValue<Hyprlang::INT>("binds:ignore_group_lock");
if (!isDirection(args)) {
Debug::log(ERR, "Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg);
@@ -2203,21 +2309,25 @@ void CKeybindManager::moveWindowOrGroup(std::string args) {
g_pCompositor->warpCursorTo(PWINDOW->middle());
} else
moveWindowOutOfGroup(PWINDOW, args);
} else if ((*PIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED) && ISWINDOWGROUP) // no target window
} else if ((*PIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED) && ISWINDOWGROUP) { // no target window
moveWindowOutOfGroup(PWINDOW, args);
} else if (!PWINDOWINDIR && !ISWINDOWGROUP) { // no target in dir and not in group
g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args);
g_pCompositor->warpCursorTo(PWINDOW->middle());
}
g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW);
}
void CKeybindManager::setIgnoreGroupLock(std::string args) {
static auto* const BIGNOREGROUPLOCK = &g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock")->intValue;
static auto PIGNOREGROUPLOCK = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock");
if (args == "toggle")
*BIGNOREGROUPLOCK = !*BIGNOREGROUPLOCK;
**PIGNOREGROUPLOCK = !**PIGNOREGROUPLOCK;
else
*BIGNOREGROUPLOCK = args == "on";
**PIGNOREGROUPLOCK = args == "on";
g_pEventManager->postEvent(SHyprIPCEvent{"ignoregrouplock", std::to_string(*BIGNOREGROUPLOCK)});
g_pEventManager->postEvent(SHyprIPCEvent{"ignoregrouplock", std::to_string(**PIGNOREGROUPLOCK)});
}
void CKeybindManager::denyWindowFromGroup(std::string args) {

View File

@@ -13,6 +13,7 @@ class CPluginSystem;
struct SKeybind {
std::string key = "";
uint32_t keycode = 0;
bool catchAll = false;
uint32_t modmask = 0;
std::string handler = "";
std::string arg = "";
@@ -42,6 +43,13 @@ struct SPressedKeyWithMods {
uint32_t keycode = 0;
uint32_t modmaskAtPressTime = 0;
bool sent = false;
std::string submapAtPress = "";
};
struct SParsedKey {
std::string key = "";
uint32_t keycode = 0;
bool catchAll = false;
};
class CKeybindManager {
@@ -57,7 +65,7 @@ class CKeybindManager {
void onSwitchOffEvent(const std::string&);
void addKeybind(SKeybind);
void removeKeybind(uint32_t, const std::string&);
void removeKeybind(uint32_t, const SParsedKey&);
uint32_t stringToModMask(std::string);
uint32_t keycodeToModifier(xkb_keycode_t);
void clearKeybinds();
@@ -70,6 +78,7 @@ class CKeybindManager {
bool m_bGroupsLocked = false;
std::list<SKeybind> m_lKeybinds;
std::list<SShortcutInhibitor> m_lShortcutInhibitors;
private:
std::deque<SPressedKeyWithMods> m_dPressedKeys;
@@ -111,6 +120,8 @@ class CKeybindManager {
static uint64_t spawnRaw(std::string);
static void toggleActiveFloating(std::string);
static void toggleActivePseudo(std::string);
static void setActiveFloating(std::string);
static void setActiveTiled(std::string);
static void changeworkspace(std::string);
static void fullscreenActive(std::string);
static void fakeFullscreenActive(std::string);
@@ -127,6 +138,7 @@ class CKeybindManager {
static void alterSplitRatio(std::string);
static void focusMonitor(std::string);
static void toggleSplit(std::string);
static void swapSplit(std::string);
static void moveCursorToCorner(std::string);
static void moveCursor(std::string);
static void workspaceOpt(std::string);
@@ -169,4 +181,6 @@ class CKeybindManager {
friend class CConfigManager;
};
static void toggleActiveFloatingCore(std::string args, std::optional<bool> floatState);
inline std::unique_ptr<CKeybindManager> g_pKeybindManager;

View File

@@ -1,5 +1,6 @@
#include "SessionLockManager.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
static void handleSurfaceMap(void* owner, void* data) {
const auto PSURFACE = (SSessionLockSurface*)owner;
@@ -14,8 +15,6 @@ static void handleSurfaceMap(void* owner, void* data) {
if (PMONITOR)
g_pHyprRenderer->damageMonitor(PMONITOR);
g_pSessionLockManager->activateLock(); // activate lock here to prevent the red screen from flashing before that
}
static void handleSurfaceCommit(void* owner, void* data) {
@@ -44,7 +43,7 @@ static void handleSurfaceDestroy(void* owner, void* data) {
void CSessionLockManager::onNewSessionLock(wlr_session_lock_v1* pWlrLock) {
static auto* const PALLOWRELOCK = &g_pConfigManager->getConfigValuePtr("misc:allow_session_lock_restore")->intValue;
static auto PALLOWRELOCK = CConfigValue<Hyprlang::INT>("misc:allow_session_lock_restore");
if (m_sSessionLock.active && (!*PALLOWRELOCK || m_sSessionLock.pWlrLock)) {
Debug::log(LOG, "Attempted to lock a locked session!");
@@ -75,6 +74,8 @@ void CSessionLockManager::onNewSessionLock(wlr_session_lock_v1* pWlrLock) {
PSURFACE->pWlrLockSurface = PWLRSURFACE;
PSURFACE->iMonitorID = PMONITOR->ID;
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PSURFACE->pWlrLockSurface->surface, PMONITOR->scale);
wlr_session_lock_surface_v1_configure(PWLRSURFACE, PMONITOR->vecSize.x, PMONITOR->vecSize.y);
PSURFACE->hyprListener_map.initCallback(&PWLRSURFACE->surface->events.map, &handleSurfaceMap, PSURFACE, "SSessionLockSurface");
@@ -94,6 +95,8 @@ void CSessionLockManager::onNewSessionLock(wlr_session_lock_v1* pWlrLock) {
m_sSessionLock.active = false;
m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers.clear();
g_pCompositor->m_sSeat.exclusiveClient = nullptr;
g_pInputManager->refocus();
@@ -123,13 +126,15 @@ void CSessionLockManager::onNewSessionLock(wlr_session_lock_v1* pWlrLock) {
pWlrLock, "wlr_session_lock_v1");
wlr_session_lock_v1_send_locked(pWlrLock);
g_pSessionLockManager->activateLock();
}
bool CSessionLockManager::isSessionLocked() {
return m_sSessionLock.active;
}
SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(const int& id) {
SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64_t id) {
for (auto& sls : m_sSessionLock.vSessionLockSurfaces) {
if (sls->iMonitorID == id) {
if (sls->mapped)
@@ -142,6 +147,20 @@ SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(const
return nullptr;
}
// We don't want the red screen to flash.
// This violates the protocol a bit, but tries to handle the missing sync between a lock surface beeing created and the red screen beeing drawn.
float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) {
const auto& NOMAPPEDSURFACETIMER = m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers.find(id);
if (NOMAPPEDSURFACETIMER == m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers.end()) {
m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers.emplace(id, CTimer());
m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers[id].reset();
return 0.f;
}
return std::clamp(NOMAPPEDSURFACETIMER->second.getSeconds() - /* delay for screencopy */ 0.5f, 0.f, 1.f);
}
bool CSessionLockManager::isSurfaceSessionLock(wlr_surface* pSurface) {
for (auto& sls : m_sSessionLock.vSessionLockSurfaces) {
if (sls->pWlrLockSurface->surface == pSurface)
@@ -153,6 +172,17 @@ bool CSessionLockManager::isSurfaceSessionLock(wlr_surface* pSurface) {
void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) {
std::erase_if(m_sSessionLock.vSessionLockSurfaces, [&](const auto& other) { return pSLS == other.get(); });
if (g_pCompositor->m_pLastFocus)
return;
for (auto& sls : m_sSessionLock.vSessionLockSurfaces) {
if (!sls->mapped)
continue;
g_pCompositor->focusSurface(sls->pWlrLockSurface->surface);
break;
}
}
void CSessionLockManager::activateLock() {

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